如何为 dll
重载 new
和 delete
运算符。我已经将重载运算符作为 dll 的一部分编写,但是与此 dll
链接的客户端不使用 overloaded new and delete
最佳答案
这是 C++ 标准在第 17.6.4.6/3 节中对此的说明:
The program's definitions (of the new / delete operators) are used instead of the default versions supplied by the implementation. Such replacement occurs prior to program startup. The program's definitions shall not be specified as
inline
. No diagnostic is required.
如果您仔细阅读,它恰好解释了您遇到的问题。这里发生了一种“第 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
)和一个依赖于将删除动态分派(dispatch)回创建对象的站点。这是受到来自 Chad Austin 的一项技术的启发。 .我做过非常相似的事情here .
关于c++ - dll 的 new 和 delete 运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11846511/