//测试代码
#include "DebugTracer.h"
//主要的思路是:
// 1.重载new,在重载的new中保存new出来的地址,new的文件名(__FILE___),new的行数(__LINE__)
//2.将该new的信息存放在一个容器中,delete时,删除一个,程序结束,还在容器中的指针,就是已经泄露的指针
int main()
{
int*p = new int;
delete p;
int *p1 = new int[10];
return 0;
}
用来控制debug下有效,release无效
#ifndef __DUBUG_TRACER_H_
#define __DUBUG_TRACER_H_
#ifndef NDEBUG
#include "Tracer.h"
#define new new(__FILE__,__LINE__)
#endif //!NDEBUG
#endif //!__DUBUG_TRACER_H_
1.重载new/delete,容器存放new信息,并在析构时打印
#ifndef __TRACER_H_
#define __TRACER_H_
#include <stdlib.h>
#include <map>
//操作符重载,全局重载
//该函数是自己new的时候,调用的,new[]底层调用的new
void* operator new(size_t size, const char* filename, const long line);
//该函数是第三方,new的时候,调用的。比如dll,库
void* operator new(size_t size);
//delete[] 他是一个单独的函数
void operator delete(void* pointer);
void operator delete[](void* pointer);
class Tracer
{
public:
Tracer();
~Tracer();
class Entry
{
public:
Entry(const char* file = nullptr, const long line = 0)
:m_file(file), m_line(line) {}
inline const char* File()
{
return m_file;
}
inline const long Line()
{
return m_line;
}
private:
const char* m_file;
const long m_line;
};
class Lock
{
public:
Lock(Tracer& tracer)
:m_Tracer(tracer)
{
m_Tracer.m_count++;
}
~Lock()
{
m_Tracer.m_count--;
}
private:
Tracer &m_Tracer;
};
void Add(void* pointer, const char* file, const long line);
void Remove(void* pointer);
void Dump();
static bool m_Ready; //是防止对象没生成,调用delete,从而导致程序重载,导致崩溃
private:
std::map<void*, Entry> m_Tracer_Info_Map;
long m_count; //是防止第三方调用了形成递归,比如new进了void* operator new(size_t size);就会在进Add,然后会再进map中的new,从而无限循环
};
#endif //!__TRACER_H_
实现文件
#include "Tracer.h"
#include "iostream"
Tracer tracer;
//static 全局定义时,需要使用类型名
bool Tracer::m_Ready = false;
void* operator new(size_t size, const char* filename, const long line)
{
void* p = malloc(size);
if (Tracer::m_Ready)
{
tracer.Add(p, filename, line);
return p;
}
return p;
}
//该函数是别人new的时候,调用的
void* operator new(size_t size)
{
void* p = malloc(size);
if (Tracer::m_Ready)
{
tracer.Add(p, "Unknow", -1);
return p;
}
return p;
}
void operator delete(void* pointer)
{
if (Tracer::m_Ready)
{
tracer.Remove(pointer);
}
free(pointer);
}
void operator delete[](void* pointer)
{
if (Tracer::m_Ready)
{
tracer.Remove(pointer);
}
free(pointer);
}
Tracer::Tracer()
{
Tracer::m_Ready = true;
m_count = 0;
}
Tracer::~Tracer()
{
Dump();
Tracer::m_Ready = false;
}
void Tracer::Add(void* pointer, const char* file, const long line)
{
if (m_count > 0)
{
return;
}
Lock(*this);
Entry temp(file, line);
m_Tracer_Info_Map.emplace(std::make_pair(pointer, std::move(temp)));
}
void Tracer::Remove(void* pointer)
{
if (m_count > 0)
{
return;
}
Lock(*this);
auto iter = m_Tracer_Info_Map.find(pointer);
if (iter != m_Tracer_Info_Map.end())
{
m_Tracer_Info_Map.erase(iter);
}
}
void Tracer::Dump()
{
if (!m_Tracer_Info_Map.empty())
{
std::cout << "内存泄露" << std::endl;
for (auto& i : m_Tracer_Info_Map)
{
std::cout << i.second.File() << ":" << i.second.Line() << std::endl;
}
}
}