Как освободить объект, который находится в записи?

Здесь у меня сложная ситуация, я думаю. Мне нужно иметь возможность освободить объект, который является полем записи. Я обычно писал бы код очистки в деструкторе, если бы это был класс. Но так как типы записей могутввести "деструктор»как можно было бы позвонитьTObject (поле) .Free; ?

Там'я буду предсказывать два типа использования:

Замена записи на новую.

Я думаю, что это использование было бы легко реализовать. Поскольку записи являются типами значений и поэтому они копируются при присваивании, я могу перегрузить оператор присваивания и освободить объекты, принадлежащие старой записи. (

Редактировать: Перегрузка назначения не былаТаблица. Тот'новая информация для меня ..)

Выход из области, где определена переменная записи.

Я могу подумать о закрытом методе, который освобождает объекты, и этот метод можно вызывать при возбуждении области видимости вручную. НО, вот тот же вопрос: как сделать его большерекордно? Такое поведение похоже на класс ...

Вот образец (и, очевидно,не по назначению):

TProperties = record
  ... some other spesific typed fields: Integers, pointers etc..
  FBaseData: Pointer;

  FAdditionalData: TList;
  //FAdditionalData: array of Pointer; this was the first intended definition
end;

Предполагать,

FAdditionalData:=TList.Crete;

вызывается в конструкторе записей или вручную в области видимости переменной записи, открывая доступ к полю как

procedure TFormX.ButtonXClick(Sender: TObject);
var
  rec: TProperties;
begin
  //rec:=TProperties.Create(with some parameters);

  rec.FAdditionalData:=TList.Create;

  //do some work with rec
end;

После выхода из области действия ButtonClickзапись не более, чемTList все еще сохраняет свое существование, что вызывает утечки памяти ...

 kludg12 окт. 2012 г., 16:41
Запись не может быть перегружена.
 The_aLiEn12 окт. 2012 г., 16:56
Я не знал об этом (никогда раньше не нуждался), но ямы узнали это сейчас :) Да, он не мог быть перегружен ...

Ответы на вопрос(2)

Я помню, что кто-то создал класс с именем TLifetimeWatcher. В основном это выглядит так:

TLifetimeWatcher = class(TInterfacedObject)
private
  fInstance: TObject;
  fProc: TProc; 
public
  constructor Create(instance: TObject); overload;
  constructor Create(instance: TObject; proc: TProc); overload;
  destructor Destroy; override;
end;

// Процесс (cleanup) будет выполнен в деструкторе, если он назначен, в противном случае экземпляр будет освобожден путем вызова метода Free.

 kludg12 окт. 2012 г., 17:06
Кто то' это Барри Келли -blog.barrkel.com/2008/09/smart-pointers-in-delphi.html
 David Heffernan12 окт. 2012 г., 17:04
Это основной подход, изложенный в моем ответе. Без реализации этоне очень полезно.
Решение Вопроса

Если в записи есть только ссылка на объект, вы можетеполучить компилятор, чтобы помочь вам. Вы несете полную ответственность за срок службы этого объекта. Вы не можете перегрузить оператор присваивания, и вы нене получить уведомление о завершении области.

Однако вы можете добавить защитный интерфейс, который будет управлять временем жизни объекта.

TMyRecord = record
  obj: TMyObject;
  guard: IInterface;
end;

Вы должны убедиться, чтоTMyObject управляет временем жизни путем подсчета ссылок. Например, производные от.TInterfacedObject

Когда вы инициализируете запись, вы делаете это:

rec.obj := TMyObject.Create;
rec.guard := rec.obj;

На данный момент,guard поле записи теперь будет управлять вашим объектомжизнь

Фактически, если вы хотите продвинуть эту идею дальше, вы можете создать специальный класс для защиты времени жизни объектов. Это больше не заставляет вас реализовыватьIInterface в вашем классе. В Интернете есть множество примеров, иллюстрирующих эту технику. Например, я предлагаю Джаррода Холлингвортастатья под названиемУмные Указателии Барри Келлис названиемУказатели с пересчетом ссылок, пересмотренные, Есть еще много там. Это'это старый трюк!

Однако обратите внимание, что у вас есть странный гибрид типа значения и ссылочного типа. На первый взгляд, записи являются типами значений. Тем не менее, этот действует как ссылочный тип. Если у вас есть другие поля в записи, которые являются типами значений, это будет еще более запутанным. Вы'Вам нужно быть очень осведомленным об этой проблеме, когда вы работаете с такой записью.

На первый взгляд, не зная больше о вашем дизайне, яБуду склонен советовать вам не помещать ссылки на объекты в записи. Они лучше подходят под ссылочные типы, то есть классы.

 The_aLiEn12 окт. 2012 г., 17:12
Я буду смотреть на эти статьи безотлагательно ...
 David Heffernan12 окт. 2012 г., 17:03
Использование динамического массива решает управление временем жизни. Вы могли бы рассмотреть возможность использования отличногоTDynArray из Synopse, чтобы упростить использование динамических массивов.
 afrazier12 окт. 2012 г., 16:51
Я бы предложил начать с последнего абзаца первым. Помещение классов в записи - это быстрый путь к ошибочному коду, еслиочень, очень осторожно с управлением жизненным циклом.
 The_aLiEn12 окт. 2012 г., 16:56
Очень информативный ответ, спасибо мистер Хеффернан .. ЯЯ буду экспериментировать с этими способами. Мне нужно обновить вопрос, чтобы быть более понятным с дизайном. Поля объектаTList <Указатель> s, но, похоже, я бы вернулся к тому, что было в первую очередь:массив указателей

Ваш ответ на вопрос