我正在维护一个大型封闭源应用程序的插件(作为dll实现)。多年来一直运作良好。但是,随着SDK的最新更新,供应商重载全局运营商new和delete。这给我带来了很多麻烦。会发生什么是我的插件分配一个字符串。我将此字符串传递给静态链接库,该库修改它(更改它的长度,从而重新分配它)。我的应用程序崩溃了。
原因当然是字符串存在于供应商分配的自定义堆上。静态链接库对此堆一无所知,并尝试在该内存上使用默认的new / delete运算符。吊杆。
现在的问题是:如何保持代码清洁并避免使用供应商的运营商?没有条件预处理器宏。我无法避免包含有问题的标题,因为它包含了2000行以上的插件所需的代码。我不能将提供的分配器传递到另一个库,因为它没有提供任何机制。我已经对供应商提出了相关问题。我不知道还能尝试什么?
附录:经过一番激烈的辩论后,我设法说服供应商再次从下一版本的SDK中删除重载。我通过简单地破解当前的SDK并手动删除重载来解决我的直接问题。感谢这个帖子中的所有建议。他们作为争论并进一步“证明”为什么重载首先是一个坏主意。
答案 0 :(得分:4)
如果您正在编译(通过标头包含)重写的新/删除运算符,则代码中所有对new / delete的调用都将使用它们。无法重新覆盖它(链接错误)或仅部分覆盖它等等。
完全覆盖全局新/删除操作符是不好的形式。这是个坏主意。如果你没有意识到为什么这是一个坏主意,你没有资格这样做。如果你确实意识到为什么这是一个坏主意,你就有资格这样做,但你通常会选择不这样做。
在您期望人们直接包含在他们的项目中的组件中,定义全局新/删除是指数级更加邪恶。作为客户,您的工作就是帮助供应商了解情况的严重性,或者不再是他们的客户。
您可以定义自定义分配器类型(请参阅此link for a good tutorial了解如何执行此操作,需要的接口等)并将其专门用于您的STL类型(它是模板参数)。
对于shared_ptr,您需要做一些不同的事情:如果您不想使用默认的“delete p”行为,它会将删除对象作为构造函数的参数。这不是自定义分配器;它只是一个普通的一元仿函数。
答案 1 :(得分:2)
是不是可以这样做:
namespace evil{
#include "evil_header.h"
}
然后evil_header宣称全局new / delete变成了邪恶:: new / evil :: delete。我怀疑如果在evil_header中声明的事物的非标题定义,这将会很好地发挥作用。
答案 2 :(得分:1)
您可以在命名空间中使用另一个新内容:
namespace MyNS {
// Declare your new/delete operators here
// and also declare a class implementing the same interface as std::allocator
// using your newly created memory management functions.
// Don't forget to put all your classes in the namespace.
// (if you don't have one already)
}
然后你可以使用所有的STL类,给它们你的分配器类型作为模板参数。
答案 3 :(得分:0)
一种选择是创建自己的重载新运算符,可以用malloc实现。
这可以定义为:
enum MyNew {EMyNew}; void *operator new(size_t size, MyNew);
然后您可以将其称为MyClass* myClass = new (EMyNew)MyClass;
由于这是根据malloc实现的,因此它应该按预期运行。唯一的挫折是你必须替换你使用new的所有实例。