When I am using Delphi Berlin 10.1 [weak] (and [unsafe]) reference, the "Supports" function and "QueryInterface" both are incrementing the reference count when given an interface variable marked with the "weak" attribute (same behavior with "unsafe" attribute).
program WeakReferences;
{$APPTYPE CONSOLE}
{$R *.res}
uses System.SysUtils;
type
IAnInterfacedObject = interface
['{351DFDA3-42CA-4A1D-8488-494CA454FD9C}']
end;
TAnInterfacedObject = class(TInterfacedObject, IAnInterfacedObject)
protected
function GetTheReferenceCount : integer;
public
constructor Create;
destructor Destroy; override;
property TheReferenceCount : integer read GetTheReferenceCount;
end;
constructor TAnInterfacedObject.Create;
begin
inherited Create;
writeln('(create AIO instance)');
end;
destructor TAnInterfacedObject.Destroy;
begin
writeln('(destroy AIO instance)');
inherited Destroy;
end;
function TAnInterfacedObject.GetTheReferenceCount : integer;
begin
Result := FRefCount;
end;
procedure WithoutSupports;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Weak]
WeakAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
WeakAIOinterfaced := AIOinstance;
writeln('create WEAK AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
procedure WithSupports_Weak;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Weak]
WeakAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
Supports(AIOinstance, IAnInterfacedObject, WeakAIOinterfaced);
writeln('create WEAK AIO interfaced with SUPPORTS; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
procedure WithSupports_Unsafe;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Unsafe]
UnsafeAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
Supports(AIOinstance, IAnInterfacedObject, UnsafeAIOinterfaced);
writeln('create UNSAFE AIO interfaced with SUPPORTS; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
procedure WithQueryInterface_Weak;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Weak]
WeakAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced.QueryInterface(IAnInterfacedObject, WeakAIOinterfaced);
writeln('create WEAK AIO interfaced with QUERYINTERFACE; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
begin
try
writeln('--Without "Supports"-------------------');
WithoutSupports;
writeln;
writeln('--With "Supports" - weak-------------------');
WithSupports_Weak;
writeln;
writeln('--With "Supports" - unsafe-------------------');
WithSupports_Unsafe;
writeln;
writeln('--With "QueryInterface" - weak-------------------');
WithQueryInterface_Weak;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
What have I missed here? Is there a "WeakSupports" function? Is this a bug or just a shortcoming of the new "weak" interfaces feature?
Delphi Supports
(one of overloads - but all other are the same considering out
parameter) function is declared as
function Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean;
and QueryInterface
as
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
Both out
parameters are not marked as [weak]
. That means that you cannot pass [weak]
or [unsafe]
interface reference to them. You can only pass strong reference to such parameter to keep reference counting in order.
From documentation Weak References:
Note: You can only pass a [Weak] variable to a var or out parameter that is also marked as [Weak]. You cannot pass a regular strong reference to a [Weak] var or out parameter.
Note: You can only pass an [Unsafe] variable to a var or out parameter that is also marked as [Unsafe]. You cannot pass a regular strong reference to an [Unsafe] var or out parameter.
Additionally your test case has another issue. Unless you are using full-ARC Delphi compilers (currently Android and iOS) you cannot store reference counted object to object reference or you will mess up reference counting. To be more precise, object references under non-ARC compilers do not contribute to reference counting, and you can only use them as temporary access points to perform some operations on object not accessible through declared interfaces. You should always have at least one interface reference to that object instance to keep reference counting in order, and prevent premature object destruction or memory leaks.
Instead of
var
AIOinstance : TAnInterfacedObject;
...
AIOinstance := TAnInterfacedObject.Create;
you should always use
var
AIOinstance : IAnInterfacedObject;
...
AIOinstance := TAnInterfacedObject.Create;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With