停止通过stl容器调用重载的new和delete运算符

时间:2011-02-09 12:31:41

标签: c++ memory-management operator-overloading instrumentation

我正在开发一个memoryleak工具。在这我正在重载new和delete运算符。它的工作正常。但我创建此工具的代码大约是15000行。我无法更改现有代码,只能将memoryleak工具函数调用到现有代码中。具有stl容器的现有代码(如列表,映射,堆栈等)。 Stl容器还调用new和delete运算符来分配或释放内存。我希望stl容器应该调用new和delete运算符,它们不是重载的new和delete。 例如:

int *iptr = new int[10] ----> should call overloaded new[]
delete [] iptr -------------> should call overloaded delete[]
map.insert(10) -------------> should call default new[] ( which are in new.h)
map.erase()  ---------------> should call default delete[] ( which are in new.h)

我该怎么办? 任何帮助都会受到重视。

抱歉,我忘了提到我正在用以下宏替换new和delete:

#define new DEBUG_NEW
#define DEBUG_NEW TrackMemory(__FILE__, __LINE__) ->* new
#define delete TrackDelete(__FILE__, __LINE__); delete

这里TrackMemory用于跟踪内存,new用于分配与delete相同的内存。 我的工具也可以正常工作但是当stl容器进入图片时它会产生错误的结果,因为它们只使用重载的新的。 请帮帮我

3 个答案:

答案 0 :(得分:2)

15000行?好吧,通过调用代码中的包装器方法替换对newdelete的所有调用(使用宏来记录__FILE____LINE__可以是第一步)并且你'我会很快完成的。

或使用现有工具,例如 valgrind

答案 1 :(得分:2)

首先编写这些'空'函数。他们将替换标准的new并自行删除:

void *operator new (size_t memorySize);
void *operator new[] (size_t memorySize);
void *operator new (size_t memorySize, const std::nothrow_t &) throw ();
void *operator new[] (size_t memorySize, const std::nothrow_t &) throw ();
void operator delete (void *memoryPointer);
void operator delete[] (void *memoryPointer);
void operator delete (void *memoryPointer, const std::nothrow_t &) throw ();
void operator delete[] (void *memoryPointer, const std::nothrow_t &) throw ();

然后编写单独的函数来分配和释放内存:

void *myNew (size-t memorySize);
void myDelete (void *memoryPointer);

在开头提到的功能中调用myNew和myDelete。

使用HeapAlloc和HeapFree实现myNew和myDelete。

然后创建一个全局变量并将其标记为(这是Visual Studio):

#pragma init_seg(lib)

这将确保您的全局变量首先被初始化,并最后清理。

到目前为止,我们已经覆盖了基础。要获得真正的泄漏报告功能,您需要在myNew函数中存储有关已分配内存的信息。

使用全局变量的析构函数来报告所有泄漏。

此外,您可以使用StackWalk获取调用堆栈,并将其存储在每个内存分配中。

有些人可能想知道为什么要这样做而不是使用其他工具:

  • 根据我的经验,Visual Studio中的泄漏报告是有限的。它没有显示调用堆栈,只显示直接调用者,这使其无意义。
  • 一些工具使用#define来替换new,delete,alloc,...但是在很多情况下这会产生问题(例如一个被称为free的类方法(在Qt中看到这个),或删除完成在标题中,但必须链接的.lib中的新内容(也见于Qt中)。)
  • 其他工具要求您制作应用程序的交互式快照,然后再进行比较。在我上面的方法中,您将获得自动泄漏报告(无需手动操作,始终在应用程序结束时,......)。

一旦拥有了自己的内存管理器,就可以开始考虑添加其他功能(例如,基于调用堆栈的内存统计,查找内存覆盖的技巧,查找在删除内存后重用内存的代码的技巧,... )。

答案 2 :(得分:0)

通过说你的操作员新载重载,你的意思并不清楚。您不能将标准运算符重载为新,因此只能在链接时替换它。当你更换它时,你将失去原有的,这是我见过的最愚蠢的设计。替代也是全球性的。您可以在某些平台(弱符号)上使用特定于平台的链接器技巧解决此问题。

您可以使用基于类的operator new执行某种查找技巧,当然您可以在放置参数上重载operator new,但我认为您的意思不是这两种。