Search code examples
delphimemory-managementinterfacefreefastmm

What is the proper way to free a form in Delphi when it was created with a reference counted interface?


Say my form is delared as TFormOther = class(TForm, IMyInterface) where

type
  IMyInterface = interface
    ['{50E7E215-A8EA-4A1C-9F1E-018E4A76DCBD}']
    procedure DoSomething;
  end;

and

TFactory = class(TInterfacedObject)
public
  procedure MakeIt;
end;

procedure TFactory.MakeIt;
var
  LMyIntf: IMyInterface;
begin
  LMyIntf :=  TFormOther.Create(nil);

  LMyIntf.DoSomething;

  // (LMyIntf as TFormOther).Free; This is wrong and gives the classic: 
  // FastMM has detected an attemp to use an interface of a freed object.
end;

If I don't free the TFormOther instance I leak memory.

I know I can do Action := TCloseAction.caFree in TFormOther.FormClose but is that the only and best way?

This Will an interface-implementing form free itself when there are no more references to it? helped a lot but did not say how one should free the form.


Solution

  • Problem with directly freeing form through its interface reference with (LMyIntf as TFormOther).Free; is that interface reference will outlive form object instance.

    When that interface goes out of scope, in the procedure epilogue, compiler inserted call to _IntfClear to finalize LMyIntf reference will eventually end up calling _Release method on already destroyed form instance.

    To avoid such scenario, you must explicitly clear the interface before you can free form. This requires additional object variable through which you can call Free to free the form.

    procedure TFactory.MakeIt;
    var
      LMyIntf: IMyInterface;
      LObj: TObject; 
    begin
      LMyIntf :=  TFormOther.Create(nil);
    
      LMyIntf.DoSomething;
    
      LObj := TObject(LMyIntf);
      LMyIntf := nil;
      LObj.Free;
    end; 
    

    When it comes to releasing the form through FromClose event handler, such release will work flawlessly only if there are no active interface references to the form at the time of the release. It is hard to say which approach is better when discussing general code, but when using FormClose event it might be harder to ensure that you don't have active interface at that moment and such code may be harder to follow.