Generics & Interfaces how to properly free instance? lazarus / 21-General ---------------------------------------------------------------------- Mr. George · 2021-07-30 22:13 Here is a code, that include Interface and implementation. Can't figure out how to properly free object in this case. Some suggestions would be appreciated. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode delphi} interface uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  Dialogs,  //{ rtti }  //Rtti,  //TypInfo,  Generics.Defaults; type   { TForm1 }   TForm1 = class(TForm)    procedure FormCreate(Sender: TObject);  private  public  end;   ISomeInterface = interface    function TestFunc(): String;    procedure Free();  end;   { TSomeInterfaceImplementation }   TSomeInterfaceImplementation = class(TSingletonImplementation, ISomeInterface)    function TestFunc(): String;  end;   { TGeneric }   TGeneric = class    SomeField: T;    destructor Destroy(); override;  end; var  Form1: TForm1; implementation {$R *.lfm} { TSomeInterfaceImplementation } function TSomeInterfaceImplementation.TestFunc(): String;begin  Result := 'ok';end; { TGeneric } destructor TGeneric.Destroy();begin  if Assigned(SomeField) then    SomeField.Free; // AV here  // FreeAndNil(SomeField);  inherited;end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var  Gen: TGeneric;begin  Gen := TGeneric.Create();  Gen.SomeField := TSomeInterfaceImplementation.Create;  Gen.Free;end; end. ---------------------------------------------------------------------- rsz · 2021-07-31 04:04 Hi, The default COM style interfaces do reference counting and because of that the compiler inserts calls to the reference counting functions in the destructor TGeneric.Destroy, which results in an access violation after the free just before the function ends in fpc_intf_decr_ref (see in Assembler). So to get the behavior you want, add {$interfaces corba} below mode delphi and don't descend from TSingletonImplementation in TSomeInterfaceImplementation. See: https://www.freepascal.org/docs- html/current/ref/refse51.html#x104-1280007.8 https://www.freepascal.org/docs- html/current/ref/refse50.html#x103-1270007.7 ---------------------------------------------------------------------- Mr. George · 2021-07-31 09:39 Thanks! From delphi documentation: TSingletonImplementation is a base for simple classes that need a basic IInterface implementation, with reference counting disabled. So, in FPC TSingletonImplementation does not behaves like in Delphi? With COBRA enabled, how one interface can be casted to another? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode delphi}{$interfaces corba} interface uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  Dialogs,  //{ rtti }  //Rtti,  //TypInfo,  Generics.Defaults; type   { TForm1 }   TForm1 = class(TForm)    procedure FormCreate(Sender: TObject);  private  public  end;   ISomeBaseInterface = interface    ['{FAB63768-8D37-412B-9BB9-5454751EC982}']    function TestFunc(): String;    procedure Free();  end;   ISomeInterface = interface(ISomeBaseInterface)    ['{FAB63768-8D37-412B-9BB9-5454751EC982}']    property prop1: String;  end;   { TSomeInterfaceImplementation }   TSomeInterfaceImplementation = class(ISomeBaseInterface)  private    fProp1: String;  public    function TestFunc(): String;    property prop1: String read fProp1 write fProp1;  end;   { TGeneric }   TGeneric = class    SomeField: T;    destructor Destroy(); override;  end; var  Form1: TForm1; implementation {$R *.lfm} { TSomeInterfaceImplementation } function TSomeInterfaceImplementation.TestFunc(): String;begin  Result := 'ok';end; { TGeneric } destructor TGeneric.Destroy();begin  if Assigned(SomeField) then    SomeField.Free;  //FreeAndNil(T(SomeField));  inherited;end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var  //Gen: TGeneric;  P:   ISomeBaseInterface;begin  //Gen := TGeneric.Create();  //Gen.SomeField := TSomeInterfaceImplementation.Create;  //Gen.Free;  P := TSomeInterfaceImplementation.Create;  with P as ISomeInterface do // <-------------- With COBRA: Class or Com interface type expected   begin   end;end; end. ---------------------------------------------------------------------- rsz · 2021-07-31 10:26 You're welcome. I don't use Delphi (or need to be compatible with it) but the documentation from Embarcadero says that TSingletonImplementation inherits from IInterface which in turn inherits from IUnknown. This is  also the case in Free Pascal. Therefore I believe it is safe to assume that the reference counting functions are also called even though it is "disabled". However if you can test and confirm that Free Pascal behaves differently then this may be a bug and would be good to report. http://docwiki.embarcadero.com/Libraries/Sydney/en/System.Generics.Def aults.TSingletonImplementation http://docwiki.embarcadero.com/Libraries/Sydney/en/System.IInterface http://docwiki.embarcadero.com/Libraries/Sydney/en/System.IUnknown http://docwiki.embarcadero.com/Libraries/Sydney/en/System.IUnknown_Met hods ---------------------------------------------------------------------- Mr. George · 2021-07-31 10:30 Ok, will check. What about interface casting when COBRA enabled, is it possible somehow? ---------------------------------------------------------------------- rsz · 2021-07-31 10:47 Yes, but in your example TSomeInterfaceImplementation does not implement ISomeInterface so you can't cast to it. I assume you meant to make TSomeInterfaceImplementation implement ISomeInterface instead of ISomeBaseInterface? Then casting would work and the P var in FormCreate would need to be of type TSomeInterfaceImplementation. ---------------------------------------------------------------------- Mr. George · 2021-07-31 10:58 QuoteI assume you meant to make TSomeInterfaceImplementation implement ISomeInterface instead of ISomeBaseInterface?No. ISomeBaseInterface is base interface for few descendant interfaces (in demo i added only one - ISomeInterface). Why so? I can add method, that will accept ISomeBaseInterface, inside, i will be sure that parameter one of few descendant interfaces. I can check for example internal field to identify exact descendant implementation and cast to proper interface. That works without COBRA, but does not work with COBRA. ---------------------------------------------------------------------- PascalDragon · 2021-08-01 10:49 Quote from: Mr. George on July 31, 2021, 12:13:35 amHere is a code, that include Interface and implementation. Can't figure out how to properly free object in this case. Some suggestions would be appreciated. As rsz said, COM-style interfaces (the default) are reference counted. As you spezialize your TGeneric<> with ISomeInterface you simply need to do the following: nothing. That's right, your destructor of TGeneric<> can simply be empty. You also don't need to export Free in ISomeInterface (with COM-style interfaces that is a really bad design as you've learned). ---------------------------------------------------------------------- Mr. George · 2021-08-01 11:42 Code from first post is pretty simple, it indeed can use ref counting and auto destruction. I use interfaces without reference count feature and auto object destruction in my old project. Main goal was to describe some requirements for classes implementations and provide ability to pass objects for different methods that must support required interface. That's why i use TSingletonImplementation. Anyway, thanks for help. Currently i already solved issue.