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

时间:2017-02-17 16:44:39

标签: delphi weak-references delphi-10.1-berlin

当我使用Delphi Berlin 10.1 [弱](和[unsafe])引用时,"支持"功能和" QueryInterface"当给定一个标有"弱"的接口变量时,两者都递增引用计数。属性(与"不安全"属性相同的行为)。

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.

我错过了什么?有没有" WeakSupports"功能?这是一个错误还是新的"弱"的缺点?接口功能?

1 个答案:

答案 0 :(得分:8)

Delphi Supports(重载之一 - 但所有其他都是相同的,考虑out参数)函数被声明为

function Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean;

QueryInterface

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

out个参数均未标记为[weak]。这意味着您无法将[weak][unsafe]接口引用传递给它们。您只能传递对此类参数的强引用,以便按顺序保持引用计数。

来自文档Weak References

  

注意:您只能将[Weak]变量传递给var或out参数   也被标记为[弱]。你不能通过常规强者   参考[弱] var或out参数。

     

注意:您只能将[Unsafe]变量传递给var或out参数   也被标记为[不安全]。你不能通过常规强者   引用[Unsafe] var或out参数。

此外,您的测试用例还有另一个问题。除非你使用完整的ARC Delphi编译器(目前是Android和iOS),否则你不能存储引用计数对象到对象引用,否则你将搞乱引用计数。更准确地说,非ARC编译器下的对象引用不会引用引用计数,您只能将它们用作临时访问点,以对无法通过声明的接口访问的对象执行某些操作。您应该始终至少有一个对该对象实例的接口引用,以便按顺序保持引用计数,并防止过早的对象破坏或内存泄漏。

而不是

 var
   AIOinstance : TAnInterfacedObject;
   ...
   AIOinstance := TAnInterfacedObject.Create;

你应该总是使用

var
  AIOinstance : IAnInterfacedObject;
  ...
  AIOinstance := TAnInterfacedObject.Create;