内存泄漏检测并覆盖新的?

时间:2009-07-14 22:37:47

标签: c++ memory-leaks unmanaged

我试图在这两篇文章的帮助下进行内存泄漏检测: http://msdn.microsoft.com/en-us/library/e5ewb1h3%28VS.80%29.aspx http://support.microsoft.com/kb/q140858/

所以在我的stdafx.h中我现在有:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)

唯一的问题是,我有一个覆盖新功能的类:

class Dummy
{    
  //overloaded new operator
  void FAR* operator new(size_t cb);
}

现在当我编译这段代码时,我得到: 错误C2059:语法错误:'常量' 错误C2091:函数返回函数

知道如何解决这个问题吗?

4 个答案:

答案 0 :(得分:10)

您可以使用pragma指令在取消过载时保存和恢复新宏。有关确切的语法,请参阅[MSDN](http://msdn.microsoft.com/en-us/library/hsttss76(VS.71).aspx)

E.g。

#pragma push_macro("new")
#undef new
void FAR* operator new(size_t cb);
#pragma pop_macro("new") 

您可以将它们放在标题中,例如

begin_new_override.h:

#ifdef new
#define NEW_WAS_DEFINED
#pragma push_macro("new")
#undef new
#endif

end_new_override.h:

#ifdef NEW_WAS_DEFINED
#undef NEW_WAS_DEFINED
#pragma pop_macro("new")
#endif

然后

#include "begin_new_override.h"
void FAR* operator new(size_t cb);
#include "end_new_override.h"

答案 1 :(得分:4)

为什么不重载operator new?而不是将new定义为不同的东西?

在全局命名空间的某处添加这些函数定义:

// operator new overloads
void* operator new( const size_t size, const char* file, int line) throw();
void* operator new( const size_t size, const size_t align, const char* file, int line) throw();
void* operator new[]( const size_t size, const char* file, int line) throw();
void* operator new[]( const size_t size, const size_t align, const char* file, int line) throw();

// can't easily overload operator delete
void operator delete( void* ptr ) throw();
void operator delete[]( void* ptr ) throw();

// matched to the operator new overload above in case of exceptions thrown during allocation
void operator delete( void* ptr, const char* file, int line) throw();
void operator delete[]( void* ptr, const char* file, int line) throw();
void operator delete( void* ptr, const size_t align, const char* file, int line) throw();
void operator delete[]( void* ptr, const size_t align, const char* file, int line) throw();

// global new/delete
void* operator new( size_t size ) throw();
void* operator new( size_t size, const std::nothrow_t& ) throw();
void* operator new( size_t size, size_t align ) throw();
void* operator new( size_t size, size_t align, const std::nothrow_t& ) throw();

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

void operator delete( void* ptr, const std::nothrow_t&) throw();
void operator delete[]( void* ptr, const std::nothrow_t&) throw();

然后,您可以定义自己的新宏,该宏调用非全局版本并实现全局版本以断言或警告它们是否被调用(以捕获任何滑动)。

#define MY_NEW(s)    new(s, __FILE__, __LINE__)

如果直接在类上调用“new”,您的类级重载将按预期工作。如果你想在课堂上打电话给MY_NEW,你可以,但你必须重新定义课程中的重载以匹配你的新课程。

答案 2 :(得分:4)

根据我的经验,在预处理器级别通过new重新定义#define是一个糟糕的主意 - 您不仅要打破operator new重载,还要放置new,并且可能其他一些事情。

让所有那些FILE和LINE宏扩展到任何地方会导致.rodata和.data部分膨胀文件字符串和行号,并且每次调用生成更多代码。

更好(如果需要更多努力)利用调试信息(例如.pdb文件)的存在并使用类似DbgHelp库的StackWalk64之类的东西来收集堆栈资讯

重载全局operator new和operator delete(array,nothrow等)的各种组合,让它们在分配和释放内存时存储和释放堆栈信息。

您甚至可以将此信息存储在类似std :: map&lt; void *,StackInfo&gt;的结构中,只需注意不要记录由地图插入引起的alloc(对于单线程,全局锁可能就足够了) app,多线程留给读者练习。)

由于您正在为任何给定的alloc记录整个堆栈,您可以进行一些漂亮的树分析,通过“函数和后代”对分配(泄漏或其他)进行分组......有时,如果跟踪复杂的泄漏,则更容易你知道整个堆栈的分配时间。

答案 3 :(得分:1)

尝试 #undef new 在课前定义 然后再次#define new new...