我写的内存管理类,高手请指点一下
/*以前去过家公司面试,有道题是:写一个内存管理类,所有的内存分配都通过类接口来实现。当时有点蒙,没做出来,我偶尔重载new和delete来扩展一些功能。用类真没做过,也听过有关内存池的,不过那是针对固定某个程序的。。。今天突然有点想法,写了段代码,不知对不对。。。
请大家从效率,语法,功能等方面给点批评和建议
注:VC6,直接贴到程序里就能用*/
// 内存管理类.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "assert.h"
#include <vector>
#include <string>
using std::string;
class CManageMemory //内存管理类,实际应用中,数据可以向某文件中写入,以便查看错误
{
protected:
typedef struct //内存信息结构
{
void *MemAdd;
int RetAdd;
char FileName[256];
int CodeLine;
}MemInfo,*lpMemInfo;
std::vector<lpMemInfo> m_MemoryList; //内存块信息表
public:
~CManageMemory()
{
assert(m_MemoryList.size()==0);
ReleaseAll();
}
#define PLACE __FILE__,__LINE__
//函数功能:记录一个已分配的内存块
//参数1:内存块的起始位置
template<typename T>
T *New(T *p ,char *file,int line)
{
#ifdef _DEBUG
if(p!=NULL)
{
int *MyEbp; //得到分配该内存块的代码的下一句位置(eip位置),以用于查找错误
__asm
{
mov MyEbp,ebp
}
lpMemInfo pNewMem = new MemInfo;
pNewMem->MemAdd = p;
pNewMem->RetAdd = *(MyEbp+1); //保存该内存块的代码的下一句位置
strcpy(pNewMem->FileName,file);
pNewMem->CodeLine=line;
m_MemoryList.push_back(pNewMem);
}
#endif
return p;
}
//函数功能:释放已分配的内存块
//参数1:内存块的起始位置
void Delete(void *p)
{
#ifdef _DEBUG
std::vector<lpMemInfo>::iterator pIter = NULL;
for(pIter=m_MemoryList.begin();pIter<m_MemoryList.end();pIter++)
{
lpMemInfo pMem = *pIter;
if(pMem->MemAdd==p)
{
m_MemoryList.erase(pIter);
pIter--;
}
}
#endif
delete p;
}
//函数功能:该函数得到某内存块的大小
//参数1:内存块的起始地址
//返回值:内存块的字节大小
template<typename T>
int GetMemSize(T *p)
{
#ifdef _DEBUG
return *((int*)((char*)p-0x10)); //通过内存块信息得到内存块大小,该信息位于首地址-16的位置
#else
return 0;
#endif
}
//函数功能:该函数释放所有未释放的内存块
void ReleaseAll()
{
#ifdef _DEBUG
std::vector<lpMemInfo>::iterator pIter = NULL;
for(pIter=m_MemoryList.begin();pIter<m_MemoryList.end();pIter++)
{
lpMemInfo pMem=*pIter;
m_MemoryList.erase(pIter);
pIter--;
delete pMem;
}
#endif
}
//函数功能:此函数返回未释放的内存块数量
int GetLeakCount()
{
#ifdef _DEBUG
return m_MemoryList.size();
#else
return 0;
#endif
}
//函数功能:此函数返回未释放内存块的信息,以便程序员调试程序
//参数1: 第N处泄露的序号,在已知泄露次数的情况下
//参数2: 地址传递,返回泄露的下一句代码位置(EIP指向的位置)
//参数3: 地址传递,分配该内存块的文件名
//参数4: 地址传递,分配该内存块的文件所在行数
//返回值:返回泄露的内存地址
void *GetLeakInfo(int index,int *RetAdd=NULL,char *file=NULL,int *line=NULL)
{
#ifdef _DEBUG
assert(index<=m_MemoryList.size());
if(RetAdd!=NULL)
{
*RetAdd=m_MemoryList[index]->RetAdd;
}
if(file!=NULL)
{
strcpy(file,m_MemoryList[index]->FileName);
}
if(line!=NULL)
{
*line=m_MemoryList[index]->CodeLine;
}
return m_MemoryList[index]->MemAdd;
#else
return 0;
#endif
}
};
class Test //测试用类
{
int a[25];
public:
int b;
Test(int size):b(size){}
};
CManageMemory g_Memory; //全局内存管理对象
void main()
{
//用来测试的类对象
Test *a=g_Memory.New(new Test(5),PLACE);
string *b=g_Memory.New(new string, PLACE);
int *c=g_Memory.New(new int[100],PLACE);
printf("共有%d处内存未释放\n\n",g_Memory.GetLeakCount());
for(int i=g_Memory.GetLeakCount()-1;i>=0;i--)//查看各处内存块的信息
{
void *address=NULL; //地址
char file[256]={0}; //所在文件
int line=0; //所在行
int code=0; //代码位置
address=g_Memory.GetLeakInfo(i,&code,file,&line);
printf("第%d处泄露的内存块首地址为%x\n",i,address); //实际应用中最好向文件中写入
printf("该内存块长度为:%d字节\n",g_Memory.GetMemSize(address));
printf("该处泄露于EIP指向%x前一句分配\n",code);
printf("该处泄露位于文件%s第%d行\n",file,line);
printf("\n");
g_Memory.Delete(address);
}
printf("共有%d处内存未释放\n\n",g_Memory.GetLeakCount());
//g_Memory.ReleaseAll();
}