问题
I always thought that the owner is responsible for destroying visual controls and that I can manually control destruction if I pass nil
as the owner.
Consider the following example:
TMyForm = class (TForm)
private
FButton : TButton;
end;
...
FButton := TButton.Create(nil); // no owner!!
FButton.Parent := Self;
I would expect this button to produce a memory leak but it doesn't and in fact the destructor of TButton
is called.
Further investigation showed that the TWinControl
destructor contains the following snippet of code:
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
which looks like it is destroying the child components (the ones with Parent
set to the control itself).
I was not expecting the parent control to destroy the control. Can anybody explain why this is happening? And who is destroying the object if I pass in an owner?
回答1:
why this is happening?
It makes sense and it's by design. What do you think should happen to orphaned child controls when the parent is destroyed? Should they suddenly start floating around as top-level windows? Probably not. Should they be re-parented to another control? Which one?
who is destroying the object if I pass in an owner?
Parent
, if it's assigned and being freed first. TWinControl
overrides TComponent
's destructor to free its child controls first (the inherited destructor is only called later). The child controls notify their Owner
about being destroyed which removes them from its list of owned components. That's why the Owner doesn't attempt to free your object again later in its destructor.
If Parent
is the same object as Owner
then the above applies, too.
If Parent
and Owner
are two different objects, and you free the Owner first, then the Owner component frees all its owned components (see TComponent's destructor). Your object is a TControl
descendant and TControl
overrides the destructor to call SetParent(nil); which removes the instance from the parent's list of child controls. That's why the parent doesn't attempt to free your object again later in its destructor.
回答2:
The earliest version I have access right now is Delphi 5 and the TWinControl
destructor has the code you posted there too, so this behaviour has been in place for a long time. And when you think about it it kind of makes sense - the Controls
are visual components and when you destroy their container (Parent) then it makes sense to destroy the childs too. The destructor of the TWinComponent can't deside for you what to do with them (hide them? reparent them to Parent.Parent? But what if the current Parent is a top level window, ie it doesn't have Parent? etc). So the designers of the VCL desided that this is the safest option to take, avoiding memory/handle leaks (especially the win handles where at premium in the early days so avoiding leaking them was probably top priority). So if you want the childs to stay you should re-parent them before destroying the container.
BTW. if you pass an Owner then TComponent.DestroyComponents;
(called by TComponent.Destroy
) destroys the component.
来源:https://stackoverflow.com/questions/7075637/delphi-ownership-confusion