我知道一个接口对象是引用计数,所以不需要手动释放它。但是,如果它有一个TObject继承的成员,我是否应该在析构函数中手动释放这个成员?
考虑以下代码:
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Classes;
type
ITestInterface = interface(IInvokable)
['{A7BDD122-7DC6-4F23-93A2-B686571AB2C8}']
procedure TestMethod;
end;
TTestObj = class(TInterfacedObject, ITestInterface)
constructor Create;
destructor Destroy; override;
private
FData: TStrings;
public
procedure TestMethod;
end;
{ TTestObj }
constructor TTestObj.Create;
begin
FData := TStringList.Create;
end;
destructor TTestObj.Destroy;
begin
Writeln('Destroy'); // This line won't apear in the console ouput as the destructor won't be called.
FData.Free; // Who guarantees this member will be freed ?
inherited;
end;
procedure TTestObj.TestMethod;
begin
Writeln('TestMethod');
end;
{ Main }
procedure Main;
var
TestObj: TTestObj;
begin
TestObj := TTestObj.Create;
TestObj.TestMethod;
TestObj := nil; // TestObj should be freed at this moment ?
end;
begin
Writeln('Program start!');
Main;
Writeln('Program end.');
Readln;
end.程序输出:
Program start!
TestMethod
Program end.这意味着构造函数没有被调用,成员FData也没有被释放?
我该怎么办?提前谢谢。
发布于 2018-02-26 07:23:34
TTestObj中的代码很好。您必须实现一个破坏FData的析构函数,就像您所做的那样。
问题就在别处。接口对象不会被销毁,因为您从未触发任何引用计数。您需要通过接口变量引用接口对象。替换
TestObj: TTestObj使用
TestObj: ITestInterface完成此更改后,接口引用代码将在首次分配给TestObj变量时添加引用。
顺便说一句,你不需要这句话
TestObj := nil当TestObj变量超出作用域时,引用计数将降至零,实现对象将被销毁。
发布于 2018-02-26 07:20:52
您必须像往常一样释放析构函数中的TStrings (除非使用ARC编译器)。
父对象(TTestObject)被自动释放-- ,但只有当它被用作接口时--而不是它引用的对象,比如FData。
您使用对象作为对象,但必须将其用作接口以获得自动引用计数:
var
TestObj: ITestInterface;但是,与TTestObject是否实现接口无关,您必须始终释放析构函数中的任何聚合对象,就像您所做的那样。
同样,只有在使用不为对象实现ARC的编译器(即,如果目标是Win32、Win64、macOS)时,上述情况才是正确的。
https://stackoverflow.com/questions/48983070
复制相似问题