Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.166.142] |
|
Сообщ.
#1
,
|
|
|
AllocMem + поля записи ссылочного типа
Очень часто приходится хранить список записей, место под которые выделяется динамически. При этом также не хочется ограничиваться лишь простыми типами данных, а использовать всю мощь ссылочных типов вроде string и DynArray. Однако при работе с ними есть некоторые тонкости. Во-первых, после выделения памяти под структуру все такие поля необходимо занулять. Почему? Рассмотрим запись type TRec = record s1: string; end; После выделения памяти через GetMem в полученной области находится случайный мусор. На месте s1 практически наверняка присутствует набор байт, который будет считаться указателем на строку. При первом же присвоении программа подумает, что в строке уже что-то есть, и попытается освободить память. Что, разумеется, приведёт к исключению. AllocMem сама обнуляет выделенную память, так что предпочтительней использовать именно её. Во-вторых, что уже сложнее, проблемы возникают при освобождении памяти. Поля ссылочного типа освобождаются неявно, с подсчётом ссылок. Если забивать их нулями, получим утечку памяти. Но и не вручную же каждый раз их все обнулять перед FreeMem! К счастью, мне удалось найти решение - выход в способности Delphi копировать записи простым присваиванием. Задача решается созданием специальной нулевой записи соответствующего типа. type TRec = record s1, s2: string; arr: array of byte; end; var ZeroRec: TRec; ... initialization ZeroMem(ZeroRec, SizeOf(ZeroRec)); ... Способ использования: var pRec: ^TRec; ... pRec := AllocMem(SizeOf(TRec)); pRec.s1 := 'wefwefwef'; pRec.s2 := '234234234'; SetLength(pRec.arr, 10); pRec^ := ZeroRec; FreeMem(pRec); Как можно убедиться, трассируя ассемблерный код на строчке pRec^ := ZeroRec, программа очищает все ссылочные поля надлежащим образом. Остаётся добавить, что у меня этот способ применяется в нескольких проектах, которые непрерывно крутятся в течение недель и месяцев, и никаких проблем не возникает. P.S. Да, конечно, можно юзать классы, но по моему глубокому убеждению, класс должен уметь сам что-то делать, запись же создана исключительно для хранения данных. Кроме того, объекты не присвоишь так же легко, как записи. Эта тема была разделена из темы "Alloc/GetMem + поля записи ссылочного типа" |