Delphi에서 인터페이스를 사용하고 참조 카운팅을 무시할 때 인터페이스가 참조 카운트 0에 도달하면 Delphi가 호출하는 theRelease 호출을 우회 할 수 있습니다._Release가 호출되지 않도록 인터페이스와 클래스를 혼합하는 방법은 무엇입니까?
하지만 클래스와 인터페이스를 혼합 할 때 (매우 유용함) _Release 메소드는 무엇이든지간에 항상 호출됩니다. 문제는 아래 샘플 코드에서 로컬 개체가 nill-ed이지만 _Release가 여전히 호출된다는 것입니다. 잘못된 메모리는 예외입니다. 응용 프로그램의 메모리 연산에 따라 nReasonObject의 이전 위치에서 _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는 실제로 nil 인 인터페이스 참조에서 호출되지 않습니다. –
무료 –
을 호출하기 전에 마지막 인터페이스 참조가 객체를 해제하지 못하도록 _AddRef를 한 번 호출하면 아무 것도 도움이되지 않습니다. @Lars. AddRef 함수는 이미 참조를 계산하지 않도록 구현되었으므로 호출해도 아무런 효과가 없습니다. 피할 필요가있는 Release 호출이고 컴파일러는 현재 참조 수에 관계없이 해당 함수에 잠재적 호출을 삽입합니다. 항상 * non-nil 변수가 필요합니다. 결론은 명시 적으로 참조를 계산하지 않더라도 객체를 해제하기 전에 인터페이스 참조 수가 0인지 확인해야한다는 것입니다. –