在Delphi中使用Interfaces並重寫引用計數時,可能會繞過Delphi在接口達到引用計數爲零時所做的調用調用。如何通過避免_Release被調用來混合接口和類?
但是 - 當混合類和接口(這是非常有用的)的_Release方法總是叫不管。問題是在下面的示例代碼中,本地對象是空的,但_Release仍然被調用 - 除非在無效內存中。根據應用程序中的內存操作,如果在已刪除的localObject的舊位置上調用_Release,或者如果未重用內存,則可能會導致異常。
所以,可以編譯器生成的呼叫到_Release是「刪除/阻止/避免/殺死/重定向/ VMT劫持/終止/砸到/等等等等等等」?如果可以實現這一點,則在Delphi中有適當的純接口。
unit TestInterfaces;
interface
uses
Classes,
SysUtils;
type
ITestInterface = interface
['{92D4D6E4-A67F-4DB4-96A9-9E1C40825F9C}']
procedure Run;
end;
TTestClass = class(TInterfacedObject, ITestInterface)
protected
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure Run;
end;
TRunTestClass = class(TObject)
protected
FlocalInterface : ITestInterface;
FlocalObject : TTestClass;
public
constructor Create;
destructor Destroy; override;
procedure Test;
end;
procedure RunTest;
procedure RunTestOnClass;
var
globalInterface : ITestInterface;
implementation
procedure RunTest;
var
localInterface : ITestInterface;
localObject : TTestClass;
begin
try
//create an object
localObject := TTestClass.Create;
//local scope
// causes _Release call when object is nilled
localInterface := localObject;
localInterface.Run;
//or global scope
// causes _Release call when exe shuts down - possibly on invalid memory location
globalInterface := localObject;
globalInterface.Run;
finally
//localInterface := nil; //--> forces _Release to be called
FreeAndNil(localObject);
end;
end;
procedure RunTestOnClass;
var
FRunTestClass : TRunTestClass;
begin
FRunTestClass := TRunTestClass.Create;
FRunTestClass.Test;
FRunTestClass.Free;
end;
{ TTheClass }
procedure TTestClass.Run;
begin
beep;
end;
function TTestClass._AddRef: Integer;
begin
result := -1;
end;
function TTestClass._Release: integer;
begin
result := -1;
end;
{ TRunTestClass }
constructor TRunTestClass.Create;
begin
FlocalObject := TTestClass.Create;
FlocalInterface := FlocalObject;
end;
destructor TRunTestClass.Destroy;
begin
//..
FlocalObject.Free;
//FlocalObject := nil;
inherited;
end;
procedure TRunTestClass.Test;
begin
FlocalInterface.Run;
end;
end.
的確。隨着「整理」,你的意思是「設爲零」,我猜?實際上,不會在接口引用上調用_Release。 –
並且調用_AddRef一次以防止在調用免費之前最後一個接口引用釋放該對象免費 –
這對@Lars不起任何作用。 AddRef函數已經實現,它不會對引用進行計數,因此調用它將不起作用。這是您需要避免的Release調用,並且編譯器將潛在的調用插入到該函數中,而不管當前的引用計數如何。它總是被稱爲非零變量。底線是,即使您沒有明確計算引用,在釋放對象之前,您必須確保接口引用的數量爲零。 –