【问题标题】:Does TInterfacedObject automatic memory management also work with C++Builder?TInterfacedObject 自动内存管理是否也适用于 C++Builder?
【发布时间】:2015-03-02 15:13:17
【问题描述】:

博客文章“Application Development with C++Builder and Delphi”说

您在 Delphi 中编写的几乎所有内容都可以在 C++Builder 中轻松使用 (...) 您可以为 Delphi 项目编写一次对象,然后 在 C++ 项目中重用它,原封不动。

TInterfacedObject 及其基于引用计数的自动内存管理怎么样,这是否也可以与 C++Builder 一起使用,而不会造成内存泄漏?还是基于 C++ 的内存管理与这种基于引用计数的接口技术不兼容?

Delphi / C++ documentation for TInterfacedObject 说(由我突出显示):

TInterfacedObject 提供基本的引用计数功能, 使其后代类在 Delphi 和 C++ 代码中都很有用

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

【问题讨论】:

    标签: delphi memory-management c++builder portability


    【解决方案1】:

    C++ 编译器不像 Delphi 那样直接在 __interfaces 上实现引用计数。但是,System 中有一个方便的模板,用于包装接口并提供引用计数,System::DelphiInterface,这就是 the standard C++ Builder way,用于编写行为类似于 Delphi 的代码。 p>

    当使用接口编译 .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,您会发现您的引用被引用计数。

    有用的阅读是entire section on DAX,C++ Builder 中新的(从 XE 开始)标准 COM 系统,它取代了 ATL。可以在早期版本的 CB 中使用它(例如,我在 2010 年使用过),但不受支持。我喜欢认为我鼓励它通过我当时与一些内部 Embarcadero 工作人员进行的一些对话得到官方支持。 (我不知道我是否真的有任何影响 - 我只是想这样 :)

    【讨论】:

    • 我是否理解正确,要使用引用计数,原始 Delphi 代码保持不变 - 只有 C++Builder 端需要应用模板并使用 di 类型?您是否遇到过值得注意的案例(Delphi 构造),其中 C++Builder 仍然使用此解决方案泄漏内存?
    • @mjn,没错。当您在 C++ Builder 中使用 Delphi 接口时,将其包装在 DelphiInterface 模板中,并始终(且仅)通过包装的 _di_ 类型引用它。如果您遵循该规则,引用计数将起作用。使用该模板我没有遇到任何内存泄漏。
    【解决方案2】:

    C++ 编译器不会发出代码来调用AddRefRelease。 C++ 中没有特殊的interface 类型。相反,您需要确保对AddRefRelease 进行必要的调用。这通常通过将原始接口包装在智能指针中来实现。在 C++-Builder 中,您可能会选择使用 DelphiInterface&lt;T&gt;TComInterface&lt;T&gt;

    Serg 在这篇文章中谈到了这个话题:Consuming Delphi interfaces in Dephi and C++。那篇文章的摘要值得重复:

    一些值得一提的细节:

    • Delphi 接口总是从 IUnknown 派生的;相应的纯抽象 C++ 类也应该定义 IUnknown 方法;
    • Delphi 接口类型是一种指向相应 C++ 抽象类的指针,因此有时我们需要在 C++ 代码;
    • Delphi 接口变量总是被编译器初始化为 nil;在 C++ 中,我们需要默认构造函数来实现 零初始化;
    • 当接口变量退出时,Delphi 接口会自动释放(即调用 IUnknown._Release 方法) 范围;在 C++ 中,我们在析构函数中实现了相同的功能;
    • Delphi 中的接口赋值隐式调用IUnknown 的_Addref 和_Release 方法;在 C++ 中,我们重载赋值运算符以正确实现接口赋值;

    【讨论】:

    • 本文专门针对从 C++ 调用 Delphi DLL。我的问题是关于在 C++Builder 项目中直接编译 Delphi / Object Pascal 代码(afaik 需要运行一些预处理器,但不涉及动态链接)
    • 无论 Delphi 代码是在 DLL 中还是在 DLL 中,C++ 编译器都不会发出引用计数。接口包装器(如智能指针)是生成对AddRefRelease 的调用的常用方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 2015-11-23
    • 1970-01-01
    相关资源
    最近更新 更多