2017-02-17 4 views
9

Когда я использую ссылку Delphi Berlin 10.1 [слабый] (и [небезопасный]), функция «Поддерживает» и «QueryInterface» увеличивают счетчик ссылок, если задана переменная интерфейса, помеченная атрибутом «слабый» (такое же поведение с атрибутом «небезопасно»).Delphi «Поддерживает» увеличивает счетчик ссылок на интерфейсах [слабый] или [небезопасный]

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»? Является ли это ошибкой или просто недостатком новых «слабых» интерфейсов?

ответ

6

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:

Примечание: Вы можете только передать [Слабое] переменную в вар или из параметра , который также помечен как [Слабый]. Вы не можете передать регулярную сильную ссылку на параметр [Слабый] var или out.

Примечание: Вы можете передать переменную [Unsafe] только в параметр var или out , который также отмечен как [Unsafe]. Вы не можете передать регулярную сильную ссылку на параметр [Unsafe] var или out.


Кроме того ваш тест имеет еще один вопрос. Если вы не используете компиляторы Full-ARC Delphi (в настоящее время Android и iOS), вы не можете магазин ссылаться на объект ссылки на объект или вы будете испортить подсчет ссылок. Точнее, ссылки на объекты в компиляторах, отличных от ARC, не способствуют подсчету ссылок, и вы можете использовать их только как временные точки доступа для выполнения некоторых операций над объектом, недоступным через объявленные интерфейсы. Вы всегда должны иметь по крайней мере одну ссылку на интерфейс к этому экземпляру объекта, чтобы вести учет ссылок в порядке и предотвращать преждевременное уничтожение объекта или утечку памяти.

Вместо

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

вы всегда должны использовать

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

Вот почему я считаю, ARC трудно смешать с не-ARC кода ... так почему я не перешел на ARC для бизнес-кода , и до сих пор сомневаюсь, что когда-нибудь буду использовать компилятор Delphi linux. –

+0

@ArnaudBouchez Я не уверен, что вы имеете в виду. Смешивание ссылок на объекты и проблем с ссылками на интерфейс - это то, что решает ARC-компилятор. Конечно, для кросс-платформенного кода вам все равно придется следовать правилам компилятора, отличным от ARC, и никогда не смешивать эти два. –

+0

Далия, есть веские причины для создания объекта с экземпляром локального объекта, а затем назначить его интерфейсу позже. Мы часто создаем и инициализируем объект и только затем назначаем его интерфейсу. – Graymatter

Смежные вопросы