jpf*_*ius 24 delphi components memory-management ownership delphi-xe
我一直认为所有者负责销毁视觉控制,如果我nil作为所有者传递,我可以手动控制销毁.
请考虑以下示例:
TMyForm = class (TForm)
private
FButton : TButton;
end;
...
FButton := TButton.Create(nil); // no owner!!
FButton.Parent := Self;
Run Code Online (Sandbox Code Playgroud)
我希望这个按钮产生内存泄漏,但它没有,实际上是析构函数TButton被调用.
进一步调查显示TWinControl析构函数包含以下代码片段:
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
Run Code Online (Sandbox Code Playgroud)
看起来它正在摧毁子组件(Parent设置为控件本身的组件).
我没想到父控件会破坏控件.任何人都可以解释为什么会这样吗?如果我通过一个所有者,谁在摧毁这个物体?
Ond*_*lle 13
为什么会这样?
它是有道理的,它是设计的.当父母被摧毁时,您认为孤儿控制会发生什么?它们应该突然开始作为顶级窗户漂浮吗?可能不是.他们应该重新成为另一个控制的父母吗?哪一个?
who is destroying the object if I pass in an owner?
Run Code Online (Sandbox Code Playgroud)
Parent,如果它被分配并首先被释放.TWinControl覆盖TComponent的析构函数来释放其子控件第一(继承析构函数只是后来被称为).子控件通知它们Owner被销毁,将其从拥有的组件列表中删除.这就是为什么所有者不会在以后的析构函数中再次尝试释放您的对象.
如果Parent是同一个对象,Owner则上述情况也适用.
如果Parent和Owner是两个不同的对象,你先自由的所有者,那么所有者成分释放其拥有的所有部件(见TComponent的析构函数).您的对象是TControl后代并TControl覆盖要调用的析构函数,该析构函数SetParent(nil);从父控件的子控件列表中删除该实例.这就是为什么父母不会在以后的析构函数中再次尝试释放你的对象的原因.
我现在访问的最早版本是Delphi 5,TWinControl析构函数也有你在那里发布的代码,所以这种行为已经存在了很长时间.当你想到它时,它是有道理的 - 它Controls是视觉组件,当你摧毁它们的容器(父)时,那么摧毁孩子也是有意义的.TWinComponent的析构函数不能告诉你如何处理它们(隐藏它们?将它们重新显示为Parent.Parent?但是如果当前Parent是顶级窗口,即它没有Parent?等等).因此,VCL的设计者们认为这是最安全的选择,避免内存/手柄泄漏(特别是在早期处于优势的胜利处理,因此避免泄漏它们可能是首要任务).因此,如果您希望孩子留下,您应该在销毁容器之前重新使用它们.
BTW.如果您通过所有者然后TComponent.DestroyComponents;(被叫TComponent.Destroy)破坏该组件.