Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2002.07.15;
Скачать: [xml.tar.bz2];

Вниз

Динамическое создание строк   Найти похожие ветки 

 
McSimm   (2002-06-26 15:12) [40]

Чтобы понятнее было почему компилятор не должен освобождать строку, можно проделать такой опыт:

AStr := AllocMem(4);
// AStr^ := "hello, world !";
Pointer(AStr^) := Pointer(123456); // произвольные 4 байта
FreeMem(AStr, 4);

Ошибки нет. Все будет работать. Только потому, что программа не будет пытаться освободить строку по отфонарному адресу


 
Skier   (2002-06-26 15:19) [41]

>McSimm
Это понятно.
Когда я писал "код ошибочен"
я имел в виду не будет ли утечки памяти.

Т.е. меня очень интересовала "внутреняя работа Delphi со
строками". (выделение памяти, подсчёт ссылок и освобождение памяти).


 
McSimm   (2002-06-26 15:30) [42]

Тут достаточно понять такую штуку.

FreeMem( указатель) освобождает выделенные 4 байта памяти в куче.
На что указывал этот указатель и были ли эти 4 байта указателем вообще - процедуре FreeMem безразлично.

Соответственно то что скрывается за указатель^ становится сиротой, если только нет других на это ссылок.

Вот пример.

S := DateToStr(Now);
AStr := @S;
FreeMem(AStr);

строка с датой проживет ровно столько, сколько проживет переменная S. И FreeMem не помешает.

Если же то же самое без переменной S - то строка будет имеет статус локальной переменной с минимальным сроком жизни. И опять же никак не зависит от FreeMem.


 
Игорь Шевченко   (2002-06-26 15:32) [43]

Если имеется локальная(ые) переменная типа String
то генерируется код:
begin
try
... тело процедуры
finally
_LStrClr(локальнаяпеременнаяString);
end;
end; { Процедуры }


 
Skier   (2002-06-26 15:39) [44]

> McSimm
Т.е. на сколько я понял подсчёт ссылок ведётся только
тогда когда строка создаётся самой Delphi

var
AStr : String;
//и т.д.

Или можно как-то ещё заставить Delphi считать ссылки ?

"FreeMem(указатель) освобождает выделенные 4 байта памяти в куче."

Мне кажеться что это не так, допустим :

type
TMyRec = packed record
mrField1 : Integer;
mrField1 : Integer;
end;
PMyRec = ^TMyRec
var
AMyRec : PMyRec;
begin
AMyRec := AllocMem(SizeOf(TMyRec));
//работа с AMyRec
FreeMem(AMyRec);
//сколько FreeMem освободит? 4 или SizeOf(TMyRec) байт ??
end;




 
Skier   (2002-06-26 15:41) [45]

> Игорь Шевченко
Это как раз понятно.


 
McSimm   (2002-06-26 15:50) [46]

сколько FreeMem освободит? 4 или SizeOf(TMyRec) байт ??
Разумеется SizeOf(TMyRec).

Кстати, обратите внимание, Если элементом TMyRec будет строка, то FreeMem(AMyRec) не освободит память от строки! только от AMyRec


 
valery_f   (2002-06-26 15:55) [47]

> McSimm © (26.06.02 15:30)
> FreeMem(указатель) освобождает выделенные 4 байта памяти

Ты хоть сам-то понял что сказал? Освобождается память !по адресу! записанному в указателе, а сам указатель (размером 4 байта) от этого никак не меняется.

> На что указывал этот указатель и были ли эти 4 байта указателем вообще - процедуре FreeMem безразлично.

Как это безразлично? Все выделенные куски памяти значатся в таблице, именно поэтому FreeMem не требует указания размера освобождаемой памяти - оно известно. Попробуй сделать FreeMem левого указателя - не знаю что там у тебя, а у меня Access violation...


 
Skier   (2002-06-26 15:58) [48]

>McSimm
А если для освобождения строки использовать
Finalize ?

Т.е.


type
TMyRec = String;
PMyRec = ^TMyRec;
var
AMyRec : PMyRec;
begin
AMyRec := AllocMem(SizeOf(TMyRec));
AMyRec^ := "hello, world !";
Finalize(AMyRec^);
FreeMem(AMyRec, SizeOf(TMyRec));
end;

?????????


 
Толик   (2002-06-26 16:04) [49]

Прошу прощения, что вмешиваюсь в столь активную беседу (очень уж интересная получается!) и посмею высказать своё мнение. Раз уж нужно формировать строки динамически, то может быть всё-таки использовать указатель на массив символов, а потом, в нужных местах заниматься приведением к типу string? Так ведь проще... Насчёт счётчика ссылок в строках - он есть только в ansistring а в string есть только размер и сами символы (если я конечно ничего не путаю). Так что моё мнение - использовать pchar + приведение типов (оно ведь память не выделяет, по крайней мере не должно).


 
Skier   (2002-06-26 16:09) [50]

> Толик

"Насчёт счётчик а ссылок в строках - он есть только в
ansistring а в string есть только размер и сами символы (если я конечно ничего не путаю)"

IMHO,путаешь.
У Марко Канту в книжке был пример про кол-во ссылок к строке.


 
McSimm   (2002-06-26 16:10) [51]

>valery_f (26.06.02 15:55)
Тут маленькое недоразумение. (Тов. Фарфуркис - устраните :)

FreeMem( указатель) освобождает выделенные 4 байта памяти потому что указатель был получен как AllocMem(4); Именно эти 4 байта (а не 4 байта указателя) и будут возвращены куче. А что в этих 4х байтах хранилось - неважно.

Так понятнее?

>А если для освобождения строки использовать
>Finalize ?
Можно. А можно использовать New-Dispose - в этой связке Finalize уже есть


 
valery_f   (2002-06-26 16:12) [52]

Только что глянул в отладчике - при выходе из процедуры локальная строка уничтожается через LStrClr. На входе у LStrClr - строка, т.е. указатель. Грубо говоря, LStrClr вычитает из этого адреса восемь байт (судя по всему - размер служебной информации) и уже для этого адреса зовет FreeMem. Так что звать FreeMem для самой строки (т.е. исходного указателя) - дохлый номер (в смысле - Access violation :)

В общем, если походить отладчиком по ассемблерному коду и глянуть сорцы, то строки вполне можно и создавать, и грохать вручную. Главное - ничего не пропустить и помнить, что от версии к версии дельфей эта схема меняется.


 
Kaban   (2002-06-26 16:13) [53]

2McSimm
>(Тов. Фарфуркис - устраните :)

а ник у тебя часом не оттуда же :-)


 
Skier   (2002-06-26 16:14) [54]

> McSimm
В последнем куске кода будет memory leak как считаешь ?
Или это те же груши только в профиль :)


 
McSimm   (2002-06-26 16:16) [55]

>Skier © (26.06.02 13:18)
Прошу понять меня правильно.
Мои высказывания носили теоретический характер, не привязанно к данной конкретной задаче. Т.е. вопрос интересен в смысле понимания внутренних механизмов работы.

Раз речь зашла о том как же лучше сделать - мой совет, использовать TStringList.
Либо PChar с приведением типов, как посоветовал Толик.

Кстати, Толик, - счетчик у строк есть.


 
Skier   (2002-06-26 16:18) [56]

> valery_f
Ну так как насчёт memory leak ?


 
Skier   (2002-06-26 16:23) [57]

>McSimm
Буду очень признателен если расскажешь
про свой подход через TStringList.
Для варианта с использованием :
1) PString = ^String
2) PVariant = ^Varinant


 
McSimm   (2002-06-26 16:25) [58]

>Skier © (26.06.02 16:18

Из вышесказанного следует, что тебя должны беспокоить две проблемы.
1. Будет ли утечка памяти
2. Проживет ли строка так долго как мне этого хотелось бы.

Ты совсем упускаешь из виду вторую проблему. Как я уже говорил легко написать такой код, когда строка будет уничтожаться менеджером строк OP не тогда когда этого хочется и ссылки AStr будут хранить указатели на свободную (или перераспределенную) память.

Поэтому лучше изменить подход. Или добиться полного взаимопонимания с диспетчером строк OP.


 
Skier   (2002-06-26 16:29) [59]

>McSimm

1) ОР - это чаво ?
2) Про TStringList расскажешь ?


 
McSimm   (2002-06-26 16:37) [60]

>Skier © (26.06.02 13:18)
OP - Object Pascal. Лень набирать было :)

Вариантов много. Для строк удобно использовать TStringList. Для общего случая можно использовать record и/или TList. Можно использовать динамические массивы.
Опять же, заменив AllocMem-FreeMem на New-Dispose можно решить проблему с минимальными затратами.

Что рассказать про TStringList? Это удобный класс для массивов строк.


 
Skier   (2002-06-26 16:41) [61]

>McSimm
"Это удобный класс для массивов строк."
Я это давно заметил :))
Ну в общем, ладно, я понял что в моём коде память течёт-таки.
Буду искать другие подходы.




 
McSimm   (2002-06-26 16:45) [62]

>Буду искать другие подходы.

var
AStr: PString;
AVar: PVariant;
AAnyRec: PMyRec;
begin
New(AStr) ; // (AVar, AAnyRec)
AStr^ := ... // (AVar, AAnyRec)
...
Dispose(AStr); // (AVar, AAnyRec)


 
McSimm   (2002-06-26 16:46) [63]

>Kaban © (26.06.02 16:13)
> а ник у тебя часом не оттуда же :-)

Вообще-то нет.
Не припомню, а что там такое было?


 
Толик   (2002-06-26 16:51) [64]

насчёт счётчика ссылок в строках:
читаем делфёвые хелпы:

1. String types:

In the default {$H+} state, the compiler interprets string (when it appears without a bracketed number after it) as AnsiString. Use the {$H–} directive to turn string into ShortString.

т.е. по умолчанию string это не string а ansistring.

2. Short strings:

A ShortString is 0 to 255 characters long. While the length of a ShortString can change dynamically, its memory is a statically allocated 256 bytes; the first byte stores the length of the string, and the remaining 255 bytes are available for characters.

так что нету счётчика ссылок у стандартного string"а, только если ansistring...


 
Skier   (2002-06-26 16:54) [65]

> McSimm
New(AStr) динамически создаёт строку и в этом случае
память не будет утекать ? Ты уверен ??

>Толик
Похоже на правду...


 
McSimm   (2002-06-26 16:55) [66]

2Толик
Зависит от того что считать стандартным string"ом ShortString или AnsiString. :)

Я привык считать стандартным AnsiString. Т.к. считаю что ShortString оставлен только для совместивмости.

В любом случае из обсуждения легко понять что речь идет именно об AnsiString


 
McSimm   (2002-06-26 17:15) [67]

и в этом случае
память не будет утекать ? Ты уверен ??


- Если каждому New будет соответствовать Dispose,
- Если в создаваемой record не будет новых заморочек с указателями (типа record A: Integer; P: PString end)
- Если не будет ошибок
То память исчезать не будет. Уверен.

PS
Хотя я, как и любой человек, могу быть уверенным в неправильных вещах и нет информации ценнее собственного опыта :)


 
Skier   (2002-06-26 17:25) [68]

>McSimm
Извини, что достаю, но всё-таки хочется до конца
разобраться.

А чем в моём случае отличаются New от GetMem(4) ?
Т.е. почему код не работает если использовать GetMem ??


 
McSimm   (2002-06-26 18:11) [69]

Я не говорил что не работает. Можно GetMem-FreeMem использовать, но с принудительной очисткой строки либо присвоением "", любо вызовом finalize.

Вариант с New-Dispose я привел как универсальный способ для хранения различных типов данных (строки, варианты и пр.)
Dispose освобождением этих типов сам озабочен :)
и не надо будет об этом заботиться :
---
For global variables, local variables, objects, and dynamic variables deallocated using Dispose, the compiler generates code that finalizes all long strings, variants, and interfaces contained by the variable when the instance is destroyed.
---


 
valery_f   (2002-06-26 18:27) [70]

Народ, похоже мы слишком далеко уехали... В исходном примере динамически создается указатель на указатель (!), и к динамическому созданию строк это отношения вообще никакого не имеет. Это больше напоминает проверку на сообразительность компилятора - догадается ли он, что на ту строку кто-то косвенно ссылается или нет.

Я бы предложил попробовать уточнить исходную постановку задачи и разобраться - стОит ли лезть в эти дебри и изобретать велосипед, путаясь в том - строку ли мы уничтожаем, указатель на нее или указатель на указатель на нее... :)


 
Skier   (2002-06-26 18:45) [71]

>valery_f
"...на сообразительность компилятора"
Да ! Именно в этом я и хотел разобраться (см.
Skier © (26.06.02 15:19) )


 
Kaban   (2002-06-27 11:02) [72]

2 McSimm
"Обитаемый остров" читал


 
McSimm   (2002-06-27 12:38) [73]

>Kaban © (27.06.02 11:02)
Понятно.
Нет, ножик я не ел :)



Страницы: 1 2 вся ветка

Форум: "Основная";
Текущий архив: 2002.07.15;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.6 MB
Время: 0.013 c
1-47301
Tahion
2002-06-30 08:42
2002.07.15
Как нарисовать образ окна?


4-47899
Alexander
2002-05-16 02:49
2002.07.15
Как поменять курсор? С LoadCursor и SetCursor разобрался, но


1-47491
Evants
2002-07-03 21:37
2002.07.15
ТListBox (правый клик)


1-47343
PTE
2002-06-27 14:10
2002.07.15
RadioButton -ы и RadioGroup


1-47487
nimble
2002-07-04 07:20
2002.07.15
Dynamic Array





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский