如何正确替换全局new和delete运算符

Posted

技术标签:

【中文标题】如何正确替换全局new和delete运算符【英文标题】:How to properly replace global new & delete operators 【发布时间】:2012-01-01 10:18:20 【问题描述】:

首先,至少有 4-5 个主题与 SO 上的主题相似。我阅读了它们中的每一个,但我觉得它们并没有真正帮助我解决这个特定问题。如果其他人发现重复的问题,我深表歉意。在发布此之前,我已经完成了我的搜索,因为这似乎是一个非常常见的问题。

我在 Windows 7 上使用 Visual Studio .NET 2003。

我有自己的 new/delete 重载,指向我自己对 malloc() 和 free() 的自定义调用以进行诊断。我的新/删除重载在一个头文件中,我已经包含在几个文件中。

问题是,代码库几乎是意大利面条,没有简单的方法可以确保所有东西都使用这些重载。第三方库包含黑盒。我们也到处使用 STL。

在我的测试中,我发现 STL 仍在混合调用我自己的 new/delete 和标准 MSVC new/delete 调用。

将我的头文件包含在数以千计的其他文件中似乎不太现实,这将花费太长时间。谁能提供一些关于如何正确有效地全局重载 new/delete 以便一切都使用我的自定义内存管理器的提示?

【问题讨论】:

如果您在一个应涵盖大部分内容的预编译头文件中全局定义运算符。或者,如果用于检测内存泄漏,您可以使用 CRT 堆函数。 【参考方案1】:

这不是它的工作原理。您替换这两个运算符,这是在 link 时完成的。您需要做的就是编写一个定义这些运算符并将其链接到组合中的单个 TU。没有其他人需要知道这一点:

// optional_ops.cpp

void * operator new(std::size_t n) throw(std::bad_alloc)

  //...

void operator delete(void * p) throw()

  //...

原则上,不需要任何头文件来声明这些函数(operator newoperator delete),因为这两个函数的声明已经被硬编码到语言中,如果你将要。但是,名称stdstd::bad_allocstd::size_t 未预先声明,因此您可能需要包含<new> 或其他一些标头来提供这些名称。

在 C++11 及更高版本中,您也可以使用 decltype(sizeof(0)) 以不需要任何类型的库的方式获取第一个参数的大小。 C++11 也有一个更简单的异常模型,没有动态异常规范(最终在 C++17 中完全从语言中删除)。

void * operator new(decltype(sizeof(0)) n) noexcept(false)

  //...

【讨论】:

链接器不会抱怨重复定义吗?我认为 ODR 适用于此。更不用说我们构建了 120 个 DLL,而且我必须在每个 DLL 项目中链接它。我想这仍然比其他选择更好。 @RobertDailey:不,特殊情况,标准涵盖,弱引用等。实际上我前几天在 GCC 中报告了一个与此有关的错误,所以对于最新版本,这甚至可以使用-fwhole-program-flto 等等(见 here 和 here。)` @RobertDailey:该标准涵盖了用户定义替换功能,因此没有违反 ODR。编译器实现这一点,方法是使标准函数成为“弱”引用,如果找到另一个同名符号,则链接器将覆盖这些引用。 是的,在 Windows 上,如果不将它们链接到每个 DLL,就无法为整个程序提供替换的新/删除函数。或者至少强制 dll 导入这些函数,但我不确定这是否有效。我认为不幸的是 DLL 以这种方式工作。在其他平台上,当共享库在程序启动时链接时,它们通常遵循与静态链接翻译单元相同的规则,因此如果您的程序替换新/删除共享库也会得到这些替换。 您可能还想覆盖new 的“no throw”版本,它有第二个参数const std::nothrow_t&(C++ 标准的一部分)【参考方案2】:

同时添加以下几行:

void *operator new[](std::size_t s) throw(std::bad_alloc)

    // TODO: implement
    return NULL;

void operator delete[](void *p) throw()

    // TODO: implement

【讨论】:

以上是关于如何正确替换全局new和delete运算符的主要内容,如果未能解决你的问题,请参考以下文章

g ++用户定义的动态链接库上的全局new和delete运算符

[g ++用户定义的动态链接库上的全局new和delete运算符

C++学习32 重载new和delete运算符

MinGW 中的全局重载运算符 new/delete

是否可以在任何地方替换全局“operator new()”?

new和delete运算符 c/c++