【问题标题】:new and delete operator overloading for dlldll的new和delete运算符重载
【发布时间】:2012-08-04 12:00:14
【问题描述】:

如何为dll 重载newdelete 运算符。我已经编写了重载运算符作为 dll 的一部分,但是与此 dll 链接的客户端不使用 overloaded new and delete

【问题讨论】:

  • 显而易见的答案是“不要那样做”。您是在自己的类上覆盖newdelete,还是尝试在应用程序中全局重新定义它们?您可以重新构建客户端应用程序,还是尝试修改预构建二进制文件的行为?

标签: c++ window new-operator


【解决方案1】:

您可以尝试编写自己的 malloc 和 delete 函数,然后创建一个 C 定义,该定义基本上包含重写 new 和 delete 的代码,并调用这些自定义 malloc 和 delete 函数。

这样你可以做一些事情,比如

MODULE_START()
// CODE HERE

MODULE_END()

这应该可以顺利进行。

【讨论】:

    【解决方案2】:

    这是 C++ 标准在第 17.6.4.6/3 节中对此的说明:

    使用程序的定义(新 / 删除操作符)而不是实现提供的默认版本。这种替换发生在程序启动之前。程序的定义不得指定为inline。无需诊断。

    如果您仔细阅读,它可以准确地解释您遇到的问题。这里发生了一种“catch 22”。

    一方面,您不能在 DLL 中编译 new/delete 运算符的定义,因为重载的 new/delete 无法动态链接(这是因为在加载之前,在静态初始化期间可能需要 new/delete DLL,因此您在加载 DLL 之前和之后会有不一致的新/删除运算符,这是未定义的行为)。

    另一方面,您不能只将 new/delete 运算符定义放在 DLL 头文件中,因为它们需要标记为 inline 以满足单一定义规则 (ODR),而后者反过来, 不满足上述条款。可能存在不将它们标记为 inline 的要求,因为标记为 inline 的函数定义具有“无链接”,导致每个翻译单元使用其自己的编译版本(或作为内联扩展),通常可以,但不适用于动态内存分配。

    上述两个捕获的动机是,为了正确性,通常需要保证使用new 分配的内存被相应的delete 运算符释放(即“一起编译”,所以说话,或两者都默认)。例如,如果您的 new/delete 运算符依赖于底层 malloc/free 调用,那么您依赖于调用 new/delete 运算符的翻译单元使用的堆,在 DLL 和可执行文件之间,不能保证此堆将是相同的(事实上,在 Windows 中,尤其是不是,这两个模块使用两个独立的堆进行动态内存分配)。

    因此,正如 Rook 所说,解决问题的方法是“不要那样做”。不要为 DLL 对象重载 new/delete 操作符,因为没有正确的方法可以正确地执行此操作,无论您以何种方式扭曲和转动代码,它总是会归结为上述相同的问题。

    您可以并且应该做的是为您的 DLL 对象使用工厂函数模式,并返回一个智能指针(例如 std::shared_ptr)和一个自定义删除器,该删除器依赖于将删除动态分派回创建对象的站点。这是受到Chad Austin 的一项技术的启发。我做了非常相似的事情here

    【讨论】:

    • Mikael,我正在阅读关于无法将定义放入 DLL 头文件中的部分,因为它们需要被标记为内联以满足单一定义规则。这不会满足 ODR 吗?在标题内部但在类外部定义... MyClass::SomeDefinition(){...}。这不会是内联的并且会满足 ODR,不是吗?
    • @clanmjc 自己试试看。如果您在类 decl 之外但在头文件中定义一个成员函数,那么它将正确编译,但当您尝试链接使用该函数的多个目标文件时,链接器会抱怨 ODR。要解决这个问题,您必须用inline 标记定义,这归结为就好像它在类声明中定义一样。所以,是的,它确实需要标记inline,无论是通过将它放在类decl中还是通过使用inline显式标记它(两种方法完全相同)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 2019-02-09
    相关资源
    最近更新 更多