Delphi子类的引用计数

11

假设我有这样的情况:

ITest = interface
 procedure somethingHere();
end;

TImpl = class(TInterfacedObject, ITest)
 procedure somethingHere();
end;

TImplSub = class(TImpl)

end;

如果我不使用try-finally语句,那么在上面的代码中,我可以使用这种代码而不会有任何内存泄漏:

var a: ITest;
begin
 a := TImpl.Create;
end;

子类也适用吗?

var a: ITest;
begin
 a := TImplSub.Create;
end;

我认为由于TImplSub是TImpl的子类,所以TImplSub继承了父类的TInterfacedObject和ITest。上面的代码会泄漏吗?

这可能与此无关,但如何检查上面的代码是否泄漏?


1
测试应该很容易,将ReportMemoryLeaksOnShutdown设置为True将在程序终止时启用简单的报告。 - nil
在表单的onCreate中设置ReportMemoryLeaksOnShutdown为@nil? - Rosanna Trevisan
我想设置时间并不重要-至少在足够早的时候。个人而言,我会在dpr文件中设置它,因为我习惯在那里查看。 - nil
什么是try-finally? - Sertac Akyuz
@SertacAkyuz a := TImpl.Create; 这段代码没有被 try finally 保护,我的意思是... - Rosanna Trevisan
2个回答

13

使用TInterfacedObject中实现的_AddRef_Release方法可以触发接口引用的引用计数。你的子类将继承该引用计数行为。

您可以使用接口引用来存储您编写的子类对象实例,实际上必须这样做(不使用接口引用来存储引用计数的对象实例会破坏引用计数机制)。

以下代码不会泄漏,并且不需要try...finally块因为销毁是自动进行的。

var a: ITest;
begin
 a := TImplSub.Create;
end;
为了检查 Windows 编译器下的内存泄漏,您可以使用 ReportMemoryLeaksOnShutdown
begin
  ReportMemoryLeaksOnShutdown := true;
  ...
end.
另一种测试对象是否在特定行为调查期间被销毁的方法是覆盖析构函数并在那里设置断点。

嗨,Dalija,我不能点赞,但我同意你的结论。谢谢! - Rosanna Trevisan
1
@Rosanna,现在你可以了;-) - Victoria
3
仅供参考,使用 ReportMemoryLeaksOnShutdown:=DebugHook<>0; 这种方式来使用 ReportMemoryLeaksOnShutdown 更为常见。我尝试简化它 :) - Dalija Prasnikar

5
感谢评论(@nil用户)的帮助,我已经成功制作了这样的测试。
type
 ITest = interface
   procedure test;
 end;

 TProva = class(TInterfacedObject, ITest)
   procedure test;
 end;

 TProvaSub = class(TProva)
   procedure testDue;
 end;

如果您尝试运行此代码(使用F9进行调试模式):

procedure TForm1.Button1Click(Sender: TObject);
var a: ITest;
begin    
 a := TProvaSub.Create;
 a.test;    
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown:=DebugHook<>0;
end;

当我关闭表格时,我没有泄漏报告。
我的结论是:TProvaSub内部包含了一个TProva(因为它是一个子类),所以它继承了_AddRef和_Release。因此,代码是正确的,不会泄漏!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接