Interfaces without reference counting
delphi
Solution
The access violation occurs because `FreeAndNil` receives an untyped var parameter that is expected to be an object reference. You are passing an interface reference which does not meet the requirement. Unfortunately you only find out at runtime. This is, in my view, the strongest point against the use of `FreeAndNil`.
Your reference counting disables lifetime management by the interface reference counting mechanism. In order to destroy an object you need to call its destructor. And in order to do that you must have access to the destructor. Your interface doesn't expose the destructor (and it should not). So, we can deduce that, in order to destroy the object, you need to have an object reference.
Here are some options:
var
obj: TPersona;
intf: IPersona;
....
obj := TPersona.Create('Fabio');
try
intf := obj;
//do stuff with intf
finally
obj.Free;
// or FreeAndNil(obj) if you prefer
end;
Or you can do it like this
var
intf: IPersona;
....
intf := TPersona.Create('Fabio');
try
//do stuff with intf
finally
(intf as TObject).Free;
end;
Problem
After reading many post on StackOverflow about the cons of using automatic reference counting for Interfaces, I started trying to manually reference counting each interface instantiation. After trying for a full afternoon I give up! Why do I get Access Violation when I call FreeAndNil(p)? What follow is a complete listing of my simple unit. ``` unit fMainForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm4 = class(TForm) btn1: TButton; procedure FormCreate(Sender: TObject); procedure btn1Click(Sender: TObject); end; type IPersona = interface(IInterface) ['{44483AA7-2A22-41E6-BA98-F3380184ACD7}'] function GetNome: string; procedure SetNome(const Value: string); property Nome: string read GetNome write SetNome; end; type TPersona = class(TObject, IPersona) strict private FNome: string; function GetNome: string; procedure SetNome(const Value: string); protected function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; public constructor Create(const ANome: string); destructor Destroy; override; end; var Form4: TForm4; implementation {$R *.dfm} procedure TForm4.FormCreate(Sender: TObject); begin ReportMemoryLeaksOnShutdown := True; end; procedure TForm4.btn1Click(Sender: TObject); var p: IPersona; begin p := TPersona.Create('Fabio'); try ShowMessage(p.Nome); finally FreeAndNil(p); end; end; constructor TPersona.Create(const ANome: string); begin inherited Create; FNome := ANome; end; destructor TPersona.Destroy; begin inherited Destroy; end; function TPersona._AddRef: Integer; begin Result := -1 end; function TPersona._Release: Integer; begin Result := -1 end; function TPersona.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE; end; function TPersona.GetNome: string; begin Result := FNome; end; procedure TPersona.SetNome(const Value: string); begin FNome := Value; end; end. ```