Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 库强制全局重载new/delete!_C++_Operator Overloading_Memory Management_New Operator_Allocation - Fatal编程技术网

C++ 库强制全局重载new/delete!

C++ 库强制全局重载new/delete!,c++,operator-overloading,memory-management,new-operator,allocation,C++,Operator Overloading,Memory Management,New Operator,Allocation,我正在为一个大型的封闭源代码应用程序维护一个插件(作为dll实现)。这几年来一直运作良好。然而,随着SDK的最新更新,供应商超载了全局操作符new和delete。这给我带来了很多麻烦。我的插件分配了一个字符串。我将这个字符串传递到一个静态链接的库中,该库对其进行修改(更改它的长度,从而重新分配它)。我的应用程序崩溃了 当然,原因是字符串位于供应商分配的自定义堆上。静态链接库对该堆一无所知,并尝试在该内存上使用默认的new/delete操作符。轰 现在的问题是:我如何保持代码干净,避免使用供应商的

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

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

现在的问题是:我如何保持代码干净,避免使用供应商的操作符?没有条件预处理器宏。我无法避免包含令人不快的标题,因为它包含了插件所需的2000行代码。我无法将提供的分配器传递到另一个库中,因为它没有提供任何机制。我已经在这件事上窃听过卖主了。我不知道我还能尝试什么


附录:经过一番激烈的辩论后,我成功说服供应商再次从SDK的下一个版本中删除重载。通过简单地破解当前SDK并手动删除重载,我已经解决了眼前的问题。谢谢你在这篇文章中提出的所有建议。它们充当了参数,并进一步“证明”了为什么重载在一开始是个坏主意。

一个选项是创建自己的重载新操作符,可以用malloc实现

这可以定义为:

enum MyNew {EMyNew}; void *operator new(size_t size, MyNew); 枚举MyNew{EMyNew}; void*运算符new(size\u t size,MyNew); 然后您可以将其称为
MyClass*MyClass=new(EMyNew)MyClass


因为这是根据malloc实现的,所以它的行为应该与预期的一样。唯一令人沮丧的是,您必须替换所有使用new的实例。

您可以在命名空间中使用另一个new:

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类,将您的分配器类型作为模板参数。

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

覆盖全局新建/删除运算符是一种糟糕的形式。这是个坏主意。如果你不知道为什么这是个坏主意,你就没有资格这么做。如果你确实意识到这是个坏主意,你有资格这样做,但你通常会选择不这样做

在您希望人们直接将其包含到项目中的组件中,定义一个全局新建/删除是非常糟糕的。作为客户,您的工作是帮助供应商了解情况的严重性,或者不再是他们的客户

您可以定义一个自定义的分配器类型(请参阅本文中关于如何定义、所需接口等的内容),并将其专门用于STL类型(它是一个模板参数)


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

难道不可能做到这一点:

namespace evil{

#include "evil_header.h"

}

然后,evil_头声明为全局new/delete的内容变成了evil::new/evil::delete。我怀疑,如果在“邪恶”标题中声明的内容有非标题定义,那么这将起到很好的作用。

不幸的是,这不是一个选项,因为我不知道或控制“我使用过的所有新实例”。想想STL、链接库等。使用自定义分配器可以克服STL
链接库应该是安全的,因为它们不是根据头文件编译的。您必须避免更改静态库吗?在这种情况下,我可以更改它,因为它是开源的。但我真的不想在每次发布新版本时都升级我的修改。我还更喜欢一个与libs一起工作的解决方案,我没有源代码访问权限…另外,您是在谈论std::string、char*s还是其他类型的字符串?如果库重新分配您的字符串并且不提供对其分配器的访问权限,您将无能为力。继续窃听他们,他们的库被破坏了。在这种特殊情况下,char*。但我认为这实际上无关紧要,因为问题仍然存在于所有分配中。将new/delete放在自己的名称空间中并不能确保它们总是被使用(该名称空间中的类型通常在其他名称空间中被引用)。事实上,这可能只会导致更多的分配器不匹配问题。定义用于STL类型的新分配器是一个正交问题,这样的类型与全局new/delete无关,不必位于任何特定的命名空间中。而且,自定义分配器不是从std::allocator派生的。请参阅我答案中的链接。更正了有关继承的错误。不过,如果在命名空间中声明了new/delete运算符,则该命名空间中的所有内容都将使用它们。当然,这并不完美(正如您所说,不在该名称空间中的其他类不会使用它们)。更好的办法是恢复原来的全球新秩序。重载时的一个好主意是使用与标准的“nothrow”new相同的重载技巧。关于被覆盖的new和delete卡住的说法是正确的。但是,我不同意您的断言,即覆盖全局new和delete是一种糟糕的形式。我已经做过,并且在其他人做过的几十个项目上工作过。不过,根据一般经验,您永远不会覆盖库中的new和delete,因为这可能会让您的用户感到痛苦。这就是为什么许多好的库遵循STL约定,允许用户为对象指定自己的分配器。但是重写new和delete对于管理系统资源非常方便,您可以这样做