Search code examples
delphidestroytinterfacedobject

Does class(TInterfacedObject) need a destructor in Delphi?


I run in this situation where Destroy() is never called.

unit Unit2;

interface

type

// Interface
ITest = Interface(IInterface)
 function IsTrue() : Boolean;
end;

TmyClass = class(TInterfacedObject, ITest)
  public
    // Interface implementation
    function IsTrue() : Boolean;

    constructor Create();
    destructor Destroy(); override;
end;

implementation

constructor TmyClass.Create();
begin
  inherited Create();
end;

destructor TmyClass.Destroy();
begin
  inherited Destroy();
end;

published
  // Property
  property IsItTrue: Boolean read IsTrue;
end.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, 
  Vcl.Dialogs, Vcl.StdCtrls, unit2;

type
  TForm1 = class(TForm)
  Button1: TButton;
  procedure FormCreate(Sender: TObject);
  procedure Button1Click(Sender: TObject);
private
  { Private declarations }
public
  { Public declarations }
end;

var
  Form1: TForm1;
  fMyClass: TmyClass;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  fMyClass.Free;  // if refcount = 0 this works, if refcount <> 0 pointer error.
  //or
  fMyClass := Nil; // no error but Destroy wil not be executed
  Close();
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  fMyClass := TMyClass.Create();
end;
end.

Reading this article, there is only a constructor but no destructor implemented.

Is there any particular reason for this?

And should I release (if needed) all other objects that will be defined in myClass by implementing a finalization section?


Solution

  • Your fMyClass variable is an object reference, not an interface, so it does not participate in TInterfaceObject's reference counting.

    You need to change this:

    fMyClass: TmyClass;

    to this:

    fMyClass: ITest;

    And then you can get rid of fMyClass.Free; altogether:

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
      System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, 
      Vcl.Dialogs, Vcl.StdCtrls, unit2;
    
    type
      TForm1 = class(TForm)
      Button1: TButton;
      procedure FormCreate(Sender: TObject);
      procedure Button1Click(Sender: TObject);
    private
      { Private declarations }
    public
      { Public declarations }
    end;
    
    var
      Form1: TForm1;
      fMyClass: ITest;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      fMyClass := nil; // no error and Destroy will be executed
      Close();
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      fMyClass := TMyClass.Create();
    end;
    
    end.
    

    fMyClass := nil; will invoke reference counting only if fMyClass is an interface variable, not an object reference, and you can't call Free() on an interface variable.