Где класс должен освобождать свои частные переменные? - PullRequest
3 голосов
/ 01 февраля 2010

Поскольку в Delphi нет сборки мусора, куда именно вы выгружаете переменные?

Скажем, у меня есть тип с набором частных переменных. Будет ли достаточно иметь метод Destroy, который выполняет эту работу? Нужно ли явно вызывать этот метод уничтожения в моих потребляющих классах?

Ответы [ 4 ]

10 голосов
/ 01 февраля 2010

Лучший способ организовать уничтожение в delphi - это всегда думать о том, «кто создаст данные переменные».

Если вы также освободите их в этом контексте (для вас, частных лиц, метод уничтожения класса), гораздо менее вероятно, что вы встретите утечки памяти.

На самом деле деструктор класса обычно не вызывается через

myInstance.Destroy();

вместо этого типичный способ сделать это через

FreeAndNil(myInstance);

или

myInstance.Free();

Поскольку delphi будет обрабатывать вызов метода деструктора в порядке

4 голосов
/ 01 февраля 2010

Объекты должны быть уничтожены, когда вы будете готовы с ними: используя .Free (который вызывает деструктор .Destroy) или FreeAndNil.

Если вы используете интерфейсы: они подсчитывают ссылки и, следовательно, они освобождаются для вас. То же самое для строк.

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

Например: в вашем TLight вы создаете TTimer, вероятно, без владельца. В этом случае вы должны освободить таймер в деструкторе класса TLight. Если бы ваш TLight был TControl или TComponent, вы могли бы создать Таймер с Собственником в качестве Владельца, и он будет автоматически освобожден при освобождении вашего экземпляра TLight.

3 голосов
/ 02 февраля 2010

Вот как я это вижу:

Типы примитивов (например, целые, вещественные, двойные, расширенные), массивы, наборы, записи: они автоматически уничтожаются при выходе из области видимости.

Типы с подсчетом ссылок (строки, типы интерфейсов, ссылки на интерфейсы): они автоматически уничтожаются, когда их счетчик ссылок равен нулю.

Объекты из классов, которые попадают в одну из этих ситуаций: не наследуются от TComponent, находятся в списке объектов, которые не реализуют владение или являются потомком TComponent, но не имеют назначенного владельца :

  • Когда их класс происходит от TInterfacesObject и доступен из ссылки на интерфейс: такое же поведение для типов счетчиков ссылок (см. Выше)
  • Другие случаи: вызов Object.Free или FreeAndNil (Object) для его ручного уничтожения (в структуре try..finally было бы еще лучше)

Объекты, которые имеют владельца (потомки TComponent или находятся в списке объектов, реализующих владение): владелец заберет их в нужное время.

Я заметил следующий комментарий от OP:

Я заметил концепцию владельца. Тем не менее, я не мог передать свой пользовательский класс метод TTimer.Create () как есть ожидая TComponent. Почему они ограничить вещи, которые будут использоваться в формах только? Разве это не окаменело плохая привычка ставить логику в свой виды (формы)?

См., Что потомок TComponent может быть зарегистрирован на паллете, чтобы иметь возможность использовать его во время разработки (например, в форме). Но это не значит, что должен !! Вы можете передать свой пользовательский класс в TTimer.Create (), если он происходит от TComponent, но вам не нужно создавать его экземпляр во время разработки - или даже принадлежать потомку TForm (если вы хотите управлять его временем жизни, вы даже не нужен владелец!).

Собственность - это механизм, помогающий людям экономить время ...

1 голос
/ 02 февраля 2010

Вы продолжаете ссылаться на «тип с частными переменными» и спрашиваете о «выгрузке переменных». Я собираюсь выйти на конечность (поскольку, возможно, я неправильно истолковал ваше сообщение), и предположить, что вы говорите о переменных класса и спрашиваете, когда эти переменные класса должны быть завершены, когда «класс выгружается». (Вы когда-нибудь занимались программированием на Java или .NET, нет; -).

Ключом к тому, что вы спрашиваете, является раздел доработки юнитов. Общая схема устройства включает 4 общих раздела, два из которых являются необязательными: инициализация и финализация.

unit Foo;
interface
  // put things here you want other units to see
implementation
  // put the *implementation* of the things from the interface here along with things
  // you only want this unit to see.
initialization
  // <optional> put code here that you want to execute when this unit is "loaded"
finalization
  // <optional> put code here that you want to execute when this unit is "unloaded"
end.

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

...