Delphi"支持"增加[弱]或[不安全]接口的引用计数

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"功能吗?这是一个错误还是新"弱"接口功能的缺点?

Dal*_*kar 8

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)

  • 我错过了什么.你怎么会得到错误的引用计数?这是工厂非常普遍的模式.http://pastebin.com/nYWgdfSe (2认同)