Is it a mistake to free the form in which MainForm is the owner?

In our existing code, we have a bunch where the form is created using MainForm as the owner (say, instead of nil), but we release it explicitly.

function SomeFunc(): Boolean; var form: TMyForm; // subclasses TForm begin with TMyForm.Create(Application.MainForm) do try ShowModal; Exit(True); finally Free; end end; 

Could this be the cause of any error or malfunction, or is it safe?

I cannot figure it out by reading the document:

http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Classes.TComponent.Owner

http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Classes.TComponent.Create

+5
source share
3 answers

Look at the source code, and you yourself can answer this question!

TForm inherits far from TComponent, if we look at the TComponent destructor, we will see this (at least in DelphiXE7):

 destructor TComponent.Destroy; begin Destroying; RemoveFreeNotifications; DestroyComponents; if FOwner <> nil then FOwner.RemoveComponent(Self); FObservers.Free; inherited Destroy; end; 

There are two important lines here:

  • DestroyComponents

This will destroy all its components upon destruction prior to the destruction of the owner himself.

  • if FOwner <> nil then FOwner.RemoveComponent(Self);

Notifies the owner that the object belonging to him no longer exists and that he should be removed from the list of components of the owner.

therefore, in your case, Application.MainForm will belong to your TMyForm instance, but when it is destroyed, it will disappear from the list of components of the main form.

In short, your code is great and will not break. But to make it clear that you are managing the component life cycle, you must pass nil as the owner in the constructor. And, as Sertac Akyuz already mentioned in the comments, you will avoid calling FOwner.RemoveComponent(Self); which will save some processor cycles ...

+8
source

This is not a mistake, but it is definitely the smell of code. The preferred way to do this (create-show-destroy modal loop):

  function SomeFunc(): Boolean; var form: TMyForm; begin form := TMyForm.Create(nil); try Result := form.ShowModal = mrOk; // this can vary, of course finally form.Release; end end; 

Please note that I do not call TForm.Free directly. Instead, I call the TForm.Release method, which is safer. From the RAD Studio help file:

Release does not destroy the form until all the event handlers of the form and the event handlers of the components in the form are finished. Release also ensures that all messages in the form's event queue are processed before the form is released. Any event handlers for the form or its children should use Release instead of Free (Delphi) or delete (C ++). Failure to do so may result in a memory access error.

+2
source

As far as I know, this is completely safe if you guarantee that your main form will not be released until your child form is shown, which becomes promiscuous. I would expect an “access violation” or “Invalid pointer operation” in ChildForm.Free, that is, if it does it this far.

In a small test case, the application actually remained stuck in the modal cycle (now destroyed) of the second form.

But since freeing up the main form is the work best left for TApplication, I think we can conclude that we are using the main form, since the owner of your child form works fine.

For the question lifecycle management aspect, see whosrdaddy's answer.

+1
source

Source: https://habr.com/ru/post/1260887/


All Articles