在C/C++中指针给编码带来的极大的方便,但是同时由于分配的指针需要编程人员自行释放内存,因此容易造成内存泄漏,C++中自带的new/delete本身没有提供内存泄漏检测的功能,不过我们可以重载这两个函数来追踪内存的分配和释放,以此来检测程序是否出现了内存泄漏。算法的思想是在new一块内存时将该块内存的地址以及出现的文件和行号信息记录到一个map数据结构中,以内存地址作为key。释放该内存时将map中的该记录删除,最后程序退出时从map结构中输出那些没有被释放的内存信息。看下面一代码。
#include <stdlib.h>
#include <iostream>
#include <map>
#include <string>
#include <string.h>
#include <vector>
using namespace std;
class Tracer
{
private:
class Entry
{
public:
Entry (char const * file, int line)
: _file (file), _line (line)
{}
Entry ()
: _file (0), _line (0)
{}
char const * File () const { return _file; }
int Line () const { return _line; }
private:
char const * _file;
int _line;
};
class Lock
{
public:
Lock (Tracer & tracer)
: _tracer (tracer)
{
_tracer.lock ();
}
~Lock ()
{
_tracer.unlock ();
}
private:
Tracer & _tracer;
};
public:
Tracer ();
~Tracer ();
void Add (void * p, char const * file, int line);
void Remove (void * p);
void Dump ();
static bool Ready;
private:
void lock () { _lockCount++; }
void unlock () { _lockCount--; }
private:
typedef std::map<void *, Entry>::iterator iterator;
std::map<void *, Entry> _map;
int _lockCount;
};
bool Tracer::Ready = false;
Tracer::Tracer():_lockCount(0)
{
Ready = true;
}
Tracer::~Tracer()
{
Ready = false;
Dump();
}
void Tracer::Dump()
{
if (_map.size() != 0)
{
cout << _map.size() << " memory leaks detected" << endl;
for (iterator itor = _map.begin(); itor != _map.end(); ++itor)
{
char const* file = itor->second.File();
int line = itor->second.Line();
cout << file << ", " << line << endl;
}
}
}
void Tracer::Add(void *p, const char *file, int line)
{
if (_lockCount > 0)
return;
Tracer::Lock lock(*this);
_map[p] = Entry(file, line);
}
void Tracer::Remove(void *p)
{
if (_lockCount > 0)
return;
Tracer::Lock lock(*this);
iterator itor = _map.find(p);
if (itor != _map.end())
_map.erase(itor);
}
/*extern*/ Tracer gNewTracer;
void* operator new (size_t size, const char* file, int line)
{
void* p = malloc(size);
if (Tracer::Ready)
gNewTracer.Add(p, file, line);
return p;
}
void operator delete(void* p, const char* file, int line)
{
if (Tracer::Ready)
gNewTracer.Remove(p);
free(p);
}
void* operator new (size_t size)
{
void* p = malloc(size);
if (Tracer::Ready)
gNewTracer.Add(p, "?", 0);
return p;
}
void operator delete(void* p)
{
if (Tracer::Ready)
gNewTracer.Remove(p);
free(p);
}
void* operator new [](size_t size, const char* file, int line)
{
void* p = malloc(size);
if (Tracer::Ready)
gNewTracer.Add(p, file, line);
return p;
}
void operator delete[](void* p, const char* file, int line)
{
if (Tracer::Ready)
gNewTracer.Remove(p);
cout <<"delete[](void* p, const char* file, int line)" <<endl;
free(p);
}
void* operator new[] (size_t size)
{
void* p = malloc(size);
if (Tracer::Ready)
gNewTracer.Add(p, "?", 0);
return p;
}
void operator delete[](void* p)
{
if (Tracer::Ready)
gNewTracer.Remove(p);
cout << "delete[](void* p)"<<endl;
free(p);
}
#define new new(__FILE__, __LINE__)
int main()
{
int * a = new int(3);
int * b = new int[3];
return 0;
}
上面代码的输出是
2 memory leaks detected
leak.cpp, 181
leak.cpp, 182
即在leak.cpp文件中的181行和182行出现了内存泄漏。