5

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

4

2 回答 2

9

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

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

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

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

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

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

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

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

于 2012-08-07T14:26:45.470 回答
0

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

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

MODULE_START()
// CODE HERE

MODULE_END()

这应该工作顺利。

于 2017-10-23T13:36:20.803 回答