如何重载new
的delete
和dll
运算符。我已经将重载运算符作为dll的一部分进行了编写,但是与此dll
链接的客户端不使用overloaded new and delete
最佳答案
这是C++标准在17.6.4.6/3节中必须说的:
如果您仔细阅读该文档,就可以正确说明您遇到的麻烦。这里发生一种“捕获22”。
一方面,您无法在DLL内编译new/delete运算符的定义,因为无法动态链接重载的new/delete(这是因为在加载DLL之前的静态初始化期间可能需要new/delete,因此在加载DLL之前和之后,新的/删除的运算符会不一致,这是未定义的行为)。
另一方面,您不能仅将新的/删除的运算符定义放在DLL头文件中,因为需要将它们标记为inline
才能满足一个定义规则(ODR),而后者又不满足以上条款。之所以要求不将其标记为inline
,可能是因为标记为inline
的函数定义具有“无链接”,导致每个翻译单元使用其自己的编译版本(或作为内联扩展),通常可以,但是不用于动态内存分配。
上面的两个捕获都是出于以下事实的动机:为了正确起见,通常需要保证分配给new
的内存是由相应的delete
运算符释放的(即,“编译在一起”,可以这么说,或者都是默认的) 。例如,如果您的new/delete运算符依赖于基础的malloc/free调用,则您依赖于DLL和可执行文件之间的调用new/delete运算符的转换单元使用的堆,则不能保证此堆将会是相同的(实际上,在Windows中,尤其是不是这样,两个模块使用两个单独的堆进行动态内存分配)。
因此,正如Rook所说,解决您的问题的方法是“不要那样做”。不要重载DLL对象的new/delete运算符,因为没有干净的方法可以正确地执行此操作,无论您以何种方式扭曲和旋转代码,它始终会归结为上述相同的问题。
您可以并且应该做的是对DLL对象使用工厂功能模式,并通过自定义删除器返回智能指针(例如std::shared_ptr
),该删除器依赖于将删除动态分配回对象所在的站点创建。这是受Chad Austin的技术启发的。我做了一些非常相似的here。