您的位置:首页 > 编程语言 > C语言/C++

C++内存泄漏处理

2016-02-28 14:05 357 查看
/*
功能: 我们重载了operator new是全局的,new运算符先调用我们重载的operator new,再调用相应的构造函数,
一般来讲都是使用placement new直接在operator new返回的指针上调用相应的构造函数。
这里如果我们重载的是类的operator new会优先调用类内的,而不是全局的,即使类内的调用错误也不会向外找了。
*/
【memchecker.h】
struct MemIns
{
void* pMem;
int m_nSize;
char m_szFileName[256];
int m_nLine;
MemIns* pNext;
};
class MemManager
{
public:
MemManager();
~MemManager();
private:
MemIns *m_pMemInsHead;
int m_nTotal;
public:
static MemManager* GetInstance();
void Append(MemIns *pMemIns);
void Remove(void *ptr);
void Dump();
};
void* operator new(size_t size, const char* szFile, int nLine);
void operator delete(void* ptr, const char* szFile, int nLine);
void operator delete(void* ptr);
void* operator new[] (size_t size, const char* szFile, int nLine);
void operator delete[](void* ptr, const char* szFile, int nLine);
void operator delete[](void* ptr);

【memchecker.cpp】
#include"memchecker.h"
#include<stdio.h>
#include <stdlib.h>
#include<malloc.h>
#include<string.h>

MemManager::MemManager()
{
m_pMemInsHead=NULL;
m_nTotal=NULL;
}

MemManager::~MemManager()
{

}

void MemManager::Append(MemIns* pMemIns)
{
pMemIns->pNext=m_pMemInsHead;
m_pMemInsHead = pMemIns;
m_nTotal+= m_pMemInsHead->m_nSize;
}

void MemManager::Remove(void* ptr)
{
MemIns* pCur = m_pMemInsHead;
MemIns* pPrev = NULL;
while(pCur)
{
if(pCur->pMem == ptr)
{
if(pPrev)
{
pPrev->pNext = pCur->pNext;
}
else
{
m_pMemInsHead = pCur->pNext;
}
m_nTotal -= pCur->m_nSize;
free(pCur);
break;
}
pPrev = pCur;
pCur = pCur->pNext;
}
}

void MemManager::Dump()
{
MemIns* pp = m_pMemInsHead;
while(pp)
{
printf( "File is %s\n", pp->m_szFileName );
printf( "Size is %d\n", pp->m_nSize );
printf( "Line is %d\n\n", pp->m_nLine );
pp = pp->pNext;
}
}

void PutEntry(void *ptr, int size, const char* szFile, int nLine)
{
MemIns* p = (MemIns*)(malloc(sizeof(MemIns)));
if(p)
{
strcpy(p->m_szFileName, szFile);
p->m_nLine = nLine;
p->pMem = ptr;
p->m_nSize = size;
MemManager::GetInstance()->Append(p);
}
}

void RemoveEntry(void* ptr)
{
MemManager::GetInstance()->Remove(ptr);
}

void* operator new(size_t size, const char* szFile, int nLine)
{
void* ptr = malloc(size);
PutEntry(ptr, size, szFile, nLine);
return ptr;
}

void operator delete(void *ptr)
{
RemoveEntry(ptr);
free(ptr);
}

void operator delete(void* ptr, const char* file, int line)
{
RemoveEntry(ptr);
free(ptr);
}

void* operator new[](size_t size, const char* szFile, int nLine)
{
void * ptr = malloc(size);
PutEntry(ptr, size, szFile, nLine);
return ptr;
}

void operator delete[](void *ptr)
{
RemoveEntry(ptr);
free(ptr);
}

void operator delete[](void* ptr ,const char* szFile, int nLine)
{
RemoveEntry(ptr);
free(ptr);
}

/*
重载new思想:
operator new的重载是可以有自定义参数的,那么我们如何利用自定义参数获取更多的信息呢,这里一个很有用的做法
就是给operator new添加两个参数:char* file, int line,这两个参数记录new运算符的位置,然后再在new时
将文件名和行号传入,这样我们就能在分配内存失败时给出提示:输出文件名和行号。
那么如何获取当前语句所在文件名和行号呢,windows提供两个宏:__FILE__和__LINE__。
利用它们可以直接获取到文件名和行号,也就是 new(__FILE__, __LINE__) 由于这些都是不变的,
因此可以再定义一个宏:#define new new(__FILE__, __LINE__)。这样我们就只需要定义这个宏,
然后重载operator new即可。
*/

#define new new(__FILE__,__LINE__)
MemManager m_memTracer;

MemManager* MemManager::GetInstance()
{
return &m_memTracer;
}

int main()
{
int *plen =new int ;
*plen=10;
//delete plen;          //注意这两次delete走的都是delete重载void*参数的,没有走参数多的那项
char *pstr=new char[35];
strcpy(pstr,"hello memory leak");
//delete[] pstr;        //同上
m_memTracer.Dump();
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: