6

我正在为一个大型闭源应用程序维护一个插件(实现为 dll)。这多年来一直运行良好。然而,随着其 SDK 的最新更新,供应商重载了全球运营商 new 和 delete。这给我带来了很多麻烦。发生的事情是我的插件分配了一个字符串。我将此字符串传递到一个静态链接库中,该库对其进行修改(更改它的长度,从而重新分配它)。我的应用程序崩溃。

原因当然是字符串存在于供应商分配的自定义堆上。静态链接库对此堆一无所知,并尝试在该内存上使用默认的 new/delete 运算符。繁荣。

现在的问题是:我怎样才能保持我的代码干净并避免使用供应商的运营商?没有条件预处理器宏。我无法避免包含有问题的标头,因为它包含我需要的插件多 2000 行代码。我无法将提供的分配器传递到另一个库,因为它没有为此提供任何机制。我已经向供应商提出了这个问题。我不知道我还能尝试什么?

附录:经过一番激烈辩论后,我设法说服供应商再次从下一版本的 SDK 中删除重载。我通过简单地破解当前的 SDK 并手动删除重载解决了我的直接问题。感谢此线程中的所有建议。它们充当了论据,并进一步“证明”了为什么重载首先是一个坏主意。

4

4 回答 4

5

如果您正在编译(通过头文件包含)一个覆盖的 new/delete 运算符,那么代码中对 new/delete 的所有调用都将使用它们。无法重新覆盖它(链接错误)或仅部分覆盖它等。

完全覆盖全局 new/delete 运算符是一种不好的形式。这是个坏主意。如果你没有意识到为什么这是一个坏主意,你就没有资格这样做。如果您确实意识到为什么这是一个坏主意,那么您就有资格这样做,但您通常会选择不这样做。

在您希望人们直接包含在他们的项目中的组件中,定义一个全局的新/删除是成倍增加的邪恶。作为客户,您的工作是帮助供应商了解情况的严重性,或者停止成为他们的客户。

您可以定义自定义分配器类型(有关如何执行此操作、所需接口等的优秀教程,请参阅此链接)并将其专门用于您的 STL 类型(它是模板参数)。

对于 shared_ptr,您需要做一些不同的事情:如果您不想要默认的“删除 p”行为,它会将删除器对象作为构造函数的参数。这不是自定义分配器;它只是一个普通的一元仿函数。

于 2010-01-05T19:19:56.567 回答
2

是不是可以这样做:

namespace evil{

#include "evil_header.h"

}

然后 evil_header 声明为全局 new/delete 的内容变为 evil::new/evil::delete。我怀疑如果在 evil_header 中声明的事物有非标题定义,这会很好地发挥作用。

于 2010-01-05T19:54:03.503 回答
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 类,将您的分配器类型作为模板参数。

于 2010-01-05T16:51:33.977 回答
0

一种选择是创建您自己的重载 new 运算符,该运算符可以根据 malloc 实现。

这可以定义为:

枚举 MyNew {EMyNew};

void *operator new(size_t size, MyNew);

然后您可以将其称为MyClass* myClass = new (EMyNew)MyClass;

由于这是根据 malloc 实现的,因此它应该按预期运行。唯一令人沮丧的是,您将不得不替换所有使用过 new 的实例。

于 2010-01-05T16:17:07.187 回答