Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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.51 MB
Время: 0.006 c
2-1246696231
Gray
2009-07-04 12:30
2009.08.30
Ккак узнать номер выделенной строки в DBGrid?


2-1246258682
Andrey K
2009-06-29 10:58
2009.08.30
TStringGrid, мыш, хинт


4-1212749135
Red_imp
2008-06-06 14:45
2009.08.30
Блокировка клавиатуры + мыши под Win XP


15-1246288695
Kerk
2009-06-29 19:18
2009.08.30
Работа в Питере


15-1246451106
@!!ex
2009-07-01 16:25
2009.08.30
ЗИЛ в Германии 45 года????





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский