Dav*_*son 11 delphi weak-references delphi-10.1-berlin
当我使用Delphi Berlin 10.1 [weak](和[unsafe])引用时,"Supports"函数和"QueryInterface"都在给定一个标有"weak"属性的接口变量时递增引用计数(与"with"相同的行为)不安全的"属性".
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.
Run Code Online (Sandbox Code Playgroud)
我错过了什么?有"WeakSupports"功能吗?这是一个错误还是新"弱"接口功能的缺点?
Delphi Supports(重载之一 - 但所有其他都是相同的考虑out参数)函数被声明为
function Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean;
Run Code Online (Sandbox Code Playgroud)
而QueryInterface作为
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
Run Code Online (Sandbox Code Playgroud)
两个out参数都没有标记为[weak].这意味着您无法传递[weak]或[unsafe]接口引用它们.您只能传递对此类参数的强引用,以便按顺序保持引用计数.
来自文档弱参考:
注意:您只能将[Weak]变量传递给也标记为[Weak]的var或out参数.您不能将常规强引用传递给[Weak] var或out参数.
注意:您只能将[Unsafe]变量传递给也标记为[Unsafe]的var或out参数.您不能将常规强引用传递给[Unsafe] var或out参数.
此外,您的测试用例有另一个问题.除非您使用完整的ARC Delphi编译器(目前是Android和iOS),否则您无法将引用计数对象存储到对象引用,否则您将搞乱引用计数.更准确地说,非ARC编译器下的对象引用不会引用引用计数,您只能将它们用作临时访问点,以对无法通过声明的接口访问的对象执行某些操作.您应始终至少有一个对该对象实例的接口引用,以便按顺序保持引用计数,并防止过早的对象破坏或内存泄漏.
代替
var
AIOinstance : TAnInterfacedObject;
...
AIOinstance := TAnInterfacedObject.Create;
Run Code Online (Sandbox Code Playgroud)
你应该经常使用
var
AIOinstance : IAnInterfacedObject;
...
AIOinstance := TAnInterfacedObject.Create;
Run Code Online (Sandbox Code Playgroud)