Путаница владения Delphi - PullRequest
       12

Путаница владения Delphi

24 голосов
/ 16 августа 2011

Я всегда думал, что владелец несет ответственность за уничтожение визуальных элементов управления и что я могу вручную управлять уничтожением, если я передам nil в качестве владельца.

Рассмотрим следующий пример:

TMyForm = class (TForm)
private
  FButton : TButton;
end;

...
FButton := TButton.Create(nil);   // no owner!!
FButton.Parent := Self;

Я ожидаю, что эта кнопка вызовет утечку памяти, но это не так, и фактически вызывается деструктор TButton.

Дальнейшие исследования показали, что деструктор TWinControl содержит следующий фрагмент кода:

I := ControlCount;
while I <> 0 do
begin
  Instance := Controls[I - 1];
  Remove(Instance);
  Instance.Destroy;
  I := ControlCount;
end;

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

Я не ожидал, что родительский элемент управления разрушит элемент управления,Кто-нибудь может объяснить, почему это происходит?И кто уничтожает объект, если я передаю его владельцу?

Ответы [ 2 ]

13 голосов
/ 16 августа 2011

почему это происходит?

Это имеет смысл, и это по замыслу.Как вы думаете, что должно случиться с осиротевшими дочерними контролями, когда родитель уничтожен?Должны ли они внезапно начать плавать как окна верхнего уровня?Возможно нет.Должны ли они быть заново связаны с другим контролем?Какой?

who is destroying the object if I pass in an owner?

Parent, если он назначен и освобождается первым.TWinControl переопределяет деструктор TComponent, чтобы освободить его дочерние элементы управления first (унаследованный деструктор вызывается только позже).Дочерние элементы управления уведомляют их Owner об уничтожении, что удаляет их из списка принадлежащих ему компонентов.Вот почему Владелец не пытается снова освободить ваш объект позже в его деструкторе.

Если Parent - это тот же объект, что и Owner, то применимо и вышеприведенное.

ЕслиParent и Owner - два разных объекта, и вы сначала освобождаете владельца, затем компонент владельца освобождает все свои собственные компоненты (см. Деструктор TComponent ).Ваш объект является потомком TControl и TControl переопределяет деструктор для вызова SetParent(nil);, который удаляет экземпляр из списка дочерних элементов родительского контроля.Вот почему родитель не пытается освободить ваш объект позже в его деструкторе.

8 голосов
/ 16 августа 2011

Самая ранняя версия, к которой у меня есть доступ сейчас, - это Delphi 5, и деструктор TWinControl также содержит код, который вы разместили там, так что это поведение существует в течение долгого времени. И когда вы думаете об этом, это имеет смысл - Controls являются визуальными компонентами, и когда вы уничтожаете их контейнер (Parent), тогда имеет смысл также уничтожать дочерние элементы. Деструктор TWinComponent не может выбрать для вас, что с ними делать (скрыть их? Переписать их в Parent.Parent? Но что если текущий Parent является окном верхнего уровня, то есть у него нет Parent? И т. Д.). Таким образом, дизайнеры VCL решили, что это самый безопасный вариант, чтобы избежать утечек памяти / дескрипторов (особенно выигрышных хэндлов, где в первые дни были премиальные, поэтому предотвращение их утечек, вероятно, было главным приоритетом). Поэтому, если вы хотите, чтобы дети остались, вы должны переопределить их, прежде чем уничтожать контейнер.

КСТАТИ. если вы передадите владельца, то TComponent.DestroyComponents; (вызывается TComponent.Destroy) уничтожит компонент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...