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?
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 - theControls
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 byTComponent.Destroy
) destroys the component.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?
Parent
, if it's assigned and being freed first.TWinControl
overridesTComponent
's destructor to free its child controls first (the inherited destructor is only called later). The child controls notify theirOwner
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 asOwner
then the above applies, too.If
Parent
andOwner
are two different objects, and you free the Owner first, then the Owner component frees all its owned components (seeTComponent
's destructor). Your object is aTControl
descendant andTControl
overrides the destructor to callSetParent(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.