先来说下实现思路:可以实现一个Trace类,调用 operator new 的时候就将指向分配内存的指针、当前文件、当前行等信息添加进Trace 成员map容器内,在调用operator delete 的时候删除这些信息。定义一个全局Trace 对象,当程序结束,对象析构时判断成员map 是否还有信息,如果有则打印出来,表示已经发生内存泄漏,从输出可以看出是哪一个文件哪一行分配了内存但没有释放掉。
DebugNew.h:
1
2 3 4 5 6 7 8 9 |
#ifndef _DEBUG_NEW_H_
#define _DEBUG_NEW_H_ #ifndef NDEBUG #endif // _DEBUG_NEW_H_ |
Trace.h:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#ifndef _TRACER_H_
#define _TRACER_H_ #include <map> #ifndef NDEBUG void *operator new(size_t size, const char *file, long line); void *operator new[](size_t size, const char *file, long line); class Tracer void Add(void *p, const char *file, long line); private: #endif // NDEBUG #endif // _TRACER_H_ |
Trace.cpp:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include <iostream>
#include "Tracer.h" #ifndef NDEBUG bool Tracer::Ready = false; Tracer::Tracer() Tracer::~Tracer() void Tracer::Add(void *p, const char *file, long line) void Tracer::Remove(void *p) void Tracer::Dump() for (it = mapEntry_.begin(); it != mapEntry_.end(); ++it) } Tracer NewTrace; void *operator new(size_t size, const char *file, long line) void operator delete(void *p) void *operator new[](size_t size, const char *file, long line) void operator delete[](void *p) |
main.cpp:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream>
using namespace std; #include "DebugNew.h" int main(void) int *p2 = new int[5]; return 0; |
#define new new(__FILE__, __LINE__);
是为了利用__FILE__, 和 __LINE__两个宏,分别代表文件名和行数。分别重载了
operator new 和 operator new[] 函数以及对应的delete,更详细的讨论可以参见这里。当全局对象NewTrace
析构时调用Dump成员
函数,如果new 和 delete 没有匹配,那么map将存在泄漏信息,并打印出来。
此外只在Debug版本(没有定义NDEBUG)才跟踪内存泄漏,所以加上#ifndef NDEBUG
... #endif
而由于一般的C++库中可能没有#define new new(__FILE__, __LINE__);
即调用的还是原始的new,但现在程序中并没有重载这种类
型的new和delete函数,故并不能跟踪类似map容器之类的内存泄漏,但一般正常使用C++库容器的话,是不会造成内存泄漏的,
C++库已经实现得比较完善了,至少比我们自己写的程序要好很多。
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范