views:

429

answers:

3

The Delphi online help says that Release should be used to remove a form from memory. However, in many examples for modal forms I have seen this construct:

MyForm := TMyForm.Create(nil);
try
  MyForm.ShowModal;
finally
  MyForm.Free;
end;

Is Free a safe way to destroy a modal form? As I can see in the source for ShowModal, Application.HandleMessage will be called until the ModalResult is not 0. Is this the reason why Free can not interfere with pending windows messages?

+2  A: 

Absolutely, and you can also use the FreeAndNil routine. The FreeAndNil routine will only free the object if it is not already nil, and also set it to nil after the free. If you call free directly on an object which has already been freed, you get an Access Violation.

MyForm := TMyForm.Create(nil); 
try 
  MyForm.ShowModal; 
finally 
  FreeAndNil(MyForm); 
end;
skamradt
Small nitpick: Free will also only free the object if it is not already nil, the second part is the important one.
mghie
If MyForm is a local variable, using FreeAndNil() is certainly overkill. MyForm.Free is sufficient, in fact MyForm.Destroy would work just as well.
Allen Bauer
+for Allen - Overuse of FreeAndNil can hide errors that would have been picked up by the compiler - it won't complain if the object may not have been initialised (usually conditional creation).This also doesn't answer the question (YES IT IS OK).
Gerry
Is there any danger here of Free being called on an object that has already been freed? If not, then it's not "far" better to use FreeAndNil. If there is danger, then FreeAndNil won't actually help in this case anyway. (Remember, you free objects, not a variables. MyForm is a variable, not an object.)
Rob Kennedy
My assumption here was that MyForm was the "global" variable created by the editor when the unit was first created. I agree with Allen IF the variable is completely local then .free is sufficient since the variable falls out of scope.
skamradt
+2  A: 

It depends. Freeing the form doesn't call the event handlers that Release does, and any messages that might have been posted to the form and are queued will not be processed. So while, in many and possibly most cases calling Free (or FreeAndNil) will work fine, it may lead to some highly weird behaviour for seemingly random reasons.

The alternative that I'd suggest is in the OnClose event set the Action to caFree, like this:

procedure FormClose(Sender : TObject; Action : TCloseAction)
begin
  Action := caFree;
end;

You can then write code like this:

TMyForm.Create(nil).ShowModal;

And you don't need to free the form specifically, since it'll free itself when it's done.

Tim Sullivan
I like the creativity this shows, but I would never use it as the code shown in the question is just the idiomatic way to do it - with your code I would always wonder if the form is freed correctly when stumbling over this after some months.
mghie
Meh, whatever you feel is best. However, this does encapsulate the functionality of the form entirely and reduces your chance for forgetting to free it.
Tim Sullivan
Setting action to caFree simply calls Release. You have to be careful if you want to access properties of the form after showmodal, in case something (broken?) calls ProcessMessages
Gerry
The CM_Release method simply calls Free() Why do you say freeing the form doesn't call the event handlers that Release does?
Darian Miller
+8  A: 

Yes, it's safe to use Free after a ShowModal call.

The cases where you need to use Release are times when you're in the middle of an event handler (eg, OnClick), where further processing after the event will have to access the form. In that case calling Release instead posts a WM_RELEASE call which doesn't free the event until the event handler is done and control has returned to the message pump (ProcessMessages/Application.Run). ShowMessage doesn't return until the event handler is finished and control makes it back up the stack, so calling Free afterwards is effectively the same place where the WM_RELEASE message would be processed otherwise.

Craig Peterson
And be careful not to have any Application.ProcessMessages calls!
Gerry