При использовании интерфейсов в Delphi и переопределении подсчета ссылок можно обойти вызовы _Release, которые Delphi выполняет, когда интерфейс достигает счетчика ссылок, равного нулю.
Но - при смешивании классов и интерфейсов (что очень полезно) метод _Release ВСЕГДА вызывается независимо от того, что.Проблема заключается в том, что в приведенном ниже примере кода локальный объект имеет нулевое значение, но _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.