Форум: "Начинающим";
Текущий архив: 2009.08.30;
Скачать: [xml.tar.bz2];
ВнизСамоосвобождающиеся данные Найти похожие ветки
← →
Лёша (2009-06-26 15:12) [0]Вопрос не по конкретной задаче, а теоритический.
Имеется объект
TDefault = class
Data: Pointer;
end;
В Data я хочу хранить разношерстные записи, например:
TAnyRec = record
Fild1, Fild2: integer;
end;
Или, для другого случая - другой рекорд.
Для этого я выделяю память под запись от
PAnyRec = ^TAnyRec;
А когда ненужна - освобождаю.
Теперь вопрос, что можно придумать, чтобы память освобождалась автоматически по уничтожению TDefault? Не меняя сам класс TDefault.
Хочу проверить правильность след. утверждений.
1. Для каждого типа хранящихся данных делаем обертку в виде интерфейса. Класс, реализующий интерфейс имеет поле типа TAnyRec. Выделять память под TAnyRec не надо. Она сама очистится, когда самоуничтожится интерфейс. Интерфейс сохраняем так:
WrapInterface: TWrapInterface;
...
Default.Data := Pointer(WrapInterface);
2. Для каждого типа хранящихся данных делаем обертку в виде дин. массива. TAnyArray = array or TAnyRec;
Данные сохраняем так:
Setlength(TAnyArray(Default.Data), 1);
TAnyArray(Default.Data)[0] := ... ;//заполняем данные
И есть еще варианы сабжа?
← →
Сергей М. © (2009-06-26 15:19) [1]
> есть еще варианы сабжа?
Data: [Ole]Variant;
Data: IUnknown;
← →
int64 (2009-06-26 15:23) [2]Это понятно.
Но у меня вопрос только для случая Data: Pointer;
← →
DVM © (2009-06-26 15:26) [3]
> чтобы память освобождалась автоматически по уничтожению
> TDefault? Не меняя сам класс TDefault.
Ну если в рекордах в свою очередь не будет строк и прочих сложных объектов, то достаточно в классе хранить еще размер рекорда, тогда просто FreeMem можно сделать будет.
← →
int64 (2009-06-26 15:28) [4]DVM © (26.06.09 15:26) [3]
> Не меняя сам класс TDefault.
Лёша
← →
RWolf © (2009-06-26 15:30) [5]Вариант — сделать TDefault абстрактным базовым, а все варианты хранения данных описать в его наследниках.
← →
int64 (2009-06-26 15:44) [6]RWolf © (26.06.09 15:30) [5]
Вы опять подходите к решению задачи. Её можно решить множеством способов.
> Вопрос не по конкретной задаче, а теоритический.
Есть указатель. По нему хранятся разные данные. Как можно хранить эти данные, не заморачиваясь об их освобождении?
Леша.
← →
int64 (2009-06-26 15:54) [7]Собственно, двух вариантов хватит.
Но такое подозрение. Подсчет ссылок для 1 и 2 будет вестись корректно? Если нет, возможно, сабж не разрешим.
Лёша.
← →
Сергей М. © (2009-06-26 15:58) [8]
> Есть указатель. По нему хранятся разные данные. Как можно
> хранить эти данные, не заморачиваясь об их освобождении?
>
Никак.
Нетипизированный указатель не относится к типу данных с управляемым временем жизни.
← →
RWolf © (2009-06-26 15:58) [9]
> Есть указатель. По нему хранятся разные данные. Как можно
> хранить эти данные, не заморачиваясь об их освобождении
Хранить в этом указателе адрес объекта, содержащего нужные данные — он сам знает, как освобождать свою память.
← →
RWolf © (2009-06-26 15:58) [10]Хранить в этом указателе адрес объекта, содержащего нужные данные — он сам знает, как освобождать свою память.
← →
int64 (2009-06-26 16:05) [11]Сергей М. © (26.06.09 15:58) [8]
Т.е. в приведенных мною 2-х вариантах будут утечки памяти.
Лёша.
← →
Сергей М. © (2009-06-26 16:08) [12]Будут, если ты не предпримешь явные телодвижения по освобождению.
А если предпримешь, то это противоречит постановке задачи - "самоосвобождение".
← →
DVM © (2009-06-26 16:16) [13]
> Лёша
Если класс не допускает модификации, то записи то модификацию допускают? Если да, то пусть первым полем записи будет число, означающее ее размер, тогда в деструкторе класса можно будет освободить область памяти, занимаемую записью.
← →
int64 (2009-06-26 16:17) [14]С интерфейсами понятно. Возможно, когда мы копируем указатель, а не ссылку, подсчет ссылок не ведется. Это я могу проверить.
А как проверить утечки при динамичиских массивах.
Почему, например, при вызовах
Setlength(TAnyArray(Default.Data), 1) будут утечки?
Лёша.
← →
int64 (2009-06-26 16:24) [15]RWolf © (26.06.09 15:58) [10]
Это означает, что вместо явного управления памяти, мы, всего лишь, явно рулим временем жизни какого-то объекта.
Шило на мыло.
Лёша
← →
int64 (2009-06-26 16:31) [16]DVM © (26.06.09 16:16) [13]
> Если класс не допускает модификации, то записи то модификацию
> допускают? Если да, то пусть первым полем записи будет число,
> означающее ее размер, тогда в деструкторе класса можно
> будет освободить область памяти, занимаемую записью.
Опять же, логику освождения данных выносим в сам TDefault (который у меня ничего об этом знать не должен).
Это то же, что мы руками выделяем-освобождаем память внешними методами.
Лёша.
← →
Сергей М. © (2009-06-26 16:35) [17]
> Почему, например, при вызовах
> Setlength(TAnyArray(Default.Data), 1) будут утечки?
Потому что чтобы их не было, при разрушении объекта TDefault надо явно вызвать, скажем, Setlength(TAnyArray(Default.Data), 0).
А это противоречит условию "самоосвобождения".
← →
Sapersky (2009-06-26 16:50) [18]Для структурных типов, содержащих управляемые указатели (длинные строки, дин. массивы) можно сделать корректное освобождение, используя TypeInfo - некое подобие "внутренней RTTI". Но ТОЛЬКО для управляемых, неуправляемые (классы, прочие указатели) в TypeInfo не входят.
Вот, например, модификация TList c автоматическим прибиванием записей:
TRecordList = class(TList)
private
FRecSize: Integer;
FTypeInfo : Pointer;
protected
function AllocNew(Src: Pointer): Pointer;
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
public
constructor Create(RecSize: Integer; TypeInfo : Pointer);
function Add(Src: Pointer): Integer;
procedure Insert(Index: Integer; Src: Pointer);
end;
{ TRecordList }
constructor TRecordList.Create(RecSize: Integer; TypeInfo: Pointer);
begin
FRecSize := RecSize; FTypeInfo := TypeInfo;
end;
procedure xInitialize(p: Pointer; typeInfo: Pointer; elemCount: Cardinal);
asm
CALL System.@InitializeArray;
end;
procedure xFinalize( P: Pointer; Info: Pointer; elemCount: integer );
asm
CALL System.@FinalizeArray;
end;
procedure xCopy( Dst, Src : Pointer; Info: Pointer; Cnt: Integer);
asm
push Cnt
CALL System.@CopyArray;
// add esp, 4 // for some reason we don"t need stack restoring
end;
function TRecordList.AllocNew(Src: Pointer): Pointer;
begin
If (FRecSize <> 0) then begin
GetMem(Result, FRecSize);
If (FTypeInfo <> nil) then xInitialize(Result, FTypeInfo, 1);
If (Src <> nil) then
If (FTypeInfo <> nil) then xCopy(Result, Src, FTypeInfo, 1)
else System.Move(Src^, Result^, FRecSize);
end else
Result := Src;
end;
function TRecordList.Add(Src: Pointer): Integer;
begin
Result := Inherited Add( AllocNew(Src) );
end;
procedure TRecordList.Insert(Index: Integer; Src: Pointer);
begin
Inherited Insert(Index, AllocNew(Src) );
end;
procedure TRecordList.Notify(Ptr: Pointer; Action: TListNotification);
begin
If (FRecSize <> 0) and (Action = lnDeleted) then begin
If (FTypeInfo <> nil) then xFinalize(Ptr, FTypeInfo, 1);
FreeMem(Ptr);
end;
Inherited Notify(Ptr, Action);
end;
Использование - для записей, не содержащих строк и пр. managed типов:
List := TRecordList.Create(SizeOf(TMyRecord), nil);
для содержащих:
List := TRecordList.Create(SizeOf(TMyRecord), TypeInfo(TMyRecord));
Ещё по теме манипуляций с TypeInfo:
http://sapersky.narod.ru/files/TypInfoEx.rar
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2009.08.30;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.008 c