TInterfacedObject自动内存管理在C++Builder中也适用吗?

3
这篇博客文章“使用C++Builder和Delphi进行应用程序开发”指出:

在 Delphi 中编写的几乎所有内容都可以轻松地在 C++Builder 中使用(...)您可以为 Delphi 项目编写一次对象,然后将其不加修改地重复使用在 C++ 项目中。

那么 TInterfacedObject 及其基于引用计数的自动内存管理如何呢?它是否也适用于 C++Builder,而不会导致内存泄漏?还是基于 C++ 的内存管理与此基于接口计数的技术不兼容?

对于 TInterfacedObject,Delphi / C++ 文档 指出(由我高亮):

TInterfacedObject 提供了基本的引用计数功能,使得它的派生类在 Delphi 和 C++ 代码中都非常有用

请注意:此问题是关于在 C++Builder 项目中直接编译 Delphi / Object Pascal 源代码(经过 C++Builder 预编译器运行后),而不是通过动态链接(DLL)。

2个回答

2
C++编译器不像Delphi那样直接在__interface上实现引用计数。然而,在System中有一个方便的模板System::DelphiInterface用于包装接口并提供引用计数,这是标准的C++ Builder方式编写与Delphi类似行为的代码。
当使用接口编译.pas文件时,会在.hpp文件中自动生成使用此模板的类型,并且还可以在您的C++代码中轻松创建它们。实际上,您可能已经看到过它们 - 使用此模板生成的类型名称都以_di_开头,例如将Delphi接口IMyInterface转换为_di_IMyInterface。以下是从帮助文件链接中直接复制的示例:
// Interface that exposes an Add(..) method
 __interface  INTERFACE_UUID("{D0C74612-9E4D-459A-9304-FACE27E3577D}") IAdder  : public    System::IInterface 
 {
    virtual int __fastcall Add(int I, int J) = 0 ;
 };
 typedef System::DelphiInterface<IAdder> _di_IAdder;

在您的C++代码中,使用_di_Adder代替IAdder,您会发现您的引用计数已经被计算。有用的阅读材料是DAX整个章节,这是C++ Builder中新的(自XE起)标准COM系统,取代了ATL。虽然在CB的早期版本中也可以使用它(例如我在2010年就使用过),但是它是不受支持的。我喜欢认为我通过与Embarcadero内部员工的一些交流促使它成为官方支持的(我不知道我是否真正有任何影响-我只是喜欢这样想:)

我理解得对吗,使用引用计数时,原始的Delphi代码保持不变 - 只有C++Builder方面需要应用模板并使用_di_类型?您是否遇到过在这种解决方案下C++Builder仍然会出现内存泄漏的值得注意的情况(Delphi构造)? - mjn
@mjn,没错。当你在C++ Builder中使用Delphi接口时,请将其包装在DelphiInterface模板中,并始终(且仅)通过包装的_di_类型引用它。如果你遵循这个规则,引用计数就会起作用。我使用这个模板还没有遇到过任何内存泄漏问题。 - David

1
C++编译器不会生成调用AddRefRelease的代码。在C++中没有特殊的interface类型。相反,您需要确保进行必要的AddRefRelease调用。通常通过将原始接口包装在智能指针中来实现。在C++ Builder中,您可以选择使用DelphiInterface<T>TComInterface<T>
Serg在这篇文章中涉及了这个主题: Consuming Delphi interfaces in Dephi and C++。该文章的总结值得重申:
一些值得注意的细节: - Delphi接口总是派生自IUnknown;相应的纯虚C++类也应定义IUnknown方法; - Delphi接口类型有点像指向相应C++抽象类的指针,因此在C++代码中有时需要一个更高层次的间接级别; - Delphi接口变量始终由编译器初始化为nil;在C++中,我们需要默认构造函数来实现nil初始化; - 当接口变量超出范围时,Delphi接口会自动释放(即调用IUnknown._Release方法);在C++中,我们在析构函数中实现相同的功能; - 在Delphi中进行接口赋值时,隐式调用IUnknown的_Addref和_Release方法;在C++中,我们重载赋值运算符以正确实现接口赋值。

本文特别介绍如何从C++中调用Delphi DLL。我的问题是关于在C++Builder项目中直接编译Delphi/Object Pascal代码(需要一些预处理器运行,但不涉及动态链接)。 - mjn
无论 Delphi 代码是在 DLL 中还是链接在一起,C++ 编译器都不会发出引用计数。接口包装器(如智能指针)通常是获取对 AddRefRelease 调用的方式。 - David Heffernan

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