避免内存泄露的方法
来源:互联网 发布:海信32寸网络电视价格 编辑:程序博客网 时间:2024/04/28 21:22
1、 问题阐述
一个大型的C++程序中最容易出现,也是最头疼的一个问题就是内存泄露,即忘记释放已经申请的内存,造成程序占用的内存不断上升,系统性能不断下降,甚至造成内存耗尽而导致程序崩溃。在Java中提供自动垃圾回收机制,程序在何时的时机将回收内存,C++语言一直没有将这种机制作为语言的内部机制,但是它也提供了足够的灵活机制,使开发人员有效地避免内存泄露。
2、 内部封装
可以将分配和释放的过程封装到一个类中,即在构造的时候申请内存,析构的时候释放内存,从而保证没有内存泄露。下面是一个简单的封装类。
#include <iostream>
#include <cstring>
using namespace std;
class AutoNewDel
{
private:
char* m_szBuf;
unsigned int m_nSize;
public:
AutoNewDel(unsigned int n=1)
{
m_szBuf=new char[n];
m_nSize=n;
};
~AutoNewDel()
{
if(m_szBuf!=NULL) //提供安全机制
{
delete[] m_szBuf; //删除字符数组
m_szBuf=NULL; //防止出现野指针
}
};
char* GetBuf()
{
return m_szBuf;
};
};
void fun()
{
AutoNewDel tmpObj(100);
char* p= tmpObj.GetBuf();
strcpy(p,"one world, one dream");
cout<<p<<endl;
}
int main()
{
fun();
cout<<"exit main"<<endl;
return 0;
}
#include <cstring>
using namespace std;
class AutoNewDel
{
private:
char* m_szBuf;
unsigned int m_nSize;
public:
AutoNewDel(unsigned int n=1)
{
m_szBuf=new char[n];
m_nSize=n;
};
~AutoNewDel()
{
if(m_szBuf!=NULL) //提供安全机制
{
delete[] m_szBuf; //删除字符数组
m_szBuf=NULL; //防止出现野指针
}
};
char* GetBuf()
{
return m_szBuf;
};
};
void fun()
{
AutoNewDel tmpObj(100);
char* p= tmpObj.GetBuf();
strcpy(p,"one world, one dream");
cout<<p<<endl;
}
int main()
{
fun();
cout<<"exit main"<<endl;
return 0;
}
在这个例子中,封装了char类型的内存分配和删除,当声明对象tmpObj时,即可获得相应的内存,而且这个内存再tmpObj对象的作用域推出时自动释放,不需要开发人员显示的调用delete来释放了,避免了由于忘记释放内存而引起的内存泄露错误。
本例给出了一个最基本的思路,但是还是存在很多问题的,比如复制构造函数和复制的问题。下面将演示这个例子的不足,修改函数fun(),增加一个赋值语句,如下:
void fun()
{
AutoNewDel tmpObj(100);
AutoNewDel tmpObj2=tmpObj;//这里是增加的语句
char* p= tmpObj.GetBuf();
strcpy(p,"one world, one dream");
cout<<p<<endl;
}
在这个类中并没有实现复制构造函数,因此编译器自动构造一个默认的复制构造函数,执行位复制操作,即将对象tmpObj的内容逐字地复制到对象tmpObj2中,两个对象中的m_szBuf指向同一块内存,当对象销毁时,m_szBuf会被销毁两次,从而造成程序错误(本博客还有一篇随笔说明相关的内容,随笔地址为:C++ primer plus第十一章 使用类的程序)。简单的解决办法就是禁止复制构造函数,在类中声明复制构造函数为私有。但是这样治标不治本,它限制类的功能实现。可以通过一个引用一个计数的方法,即避免了对同一块内存的多次删除,也允许复制构造函数。{
AutoNewDel tmpObj(100);
AutoNewDel tmpObj2=tmpObj;//这里是增加的语句
char* p= tmpObj.GetBuf();
strcpy(p,"one world, one dream");
cout<<p<<endl;
}
引用的计数的原理是这样的,就是对要使用的内存维护一个计数器,记录当前有多少指针指向这块内存。当有指针指向这块内存时,计数器加1;反之,当指向这块内存指针销毁时,计数器减1。当这块内存的计数器为0时,才允许删除这块内存。可以在类的构造函数和析构函数中分别完成加1和减1的操作。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
class AutoNewDel
{
// Attribute
private:
char* m_szBuf;
unsigned int m_nSize;
int * m_count; //新增加的语句
public:
AutoNewDel(unsigned int n=1)//在构造函数中申请内存
{
m_szBuf=new char[n];
m_nSize=n;
//新增加的语句
m_count=new int;
*m_count=1;
cout<<"count is : "<<*m_count<<endl;
};
//新增加的复制构造函数
AutoNewDel(const AutoNewDel & s)
{
m_nSize=s.m_nSize;
m_szBuf=s.m_szBuf;
m_count=s.m_count;
(*m_count)++;
cout<<"count is : "<<*m_count<<endl;
}
~AutoNewDel()
{
(*m_count)--;
cout<<"count is : "<<*m_count<<endl;//新增加的两条语句
if(*m_count==0)
{
cout<<"buf is deleted"<<endl;
if(m_szBuf!=NULL) //提供安全机制
{
delete[] m_szBuf; //删除字符数组
m_szBuf=NULL; //防止出现野指针
if(m_count!=NULL)
{
delete m_count;
m_count=NULL;
}
}
}
};
char* GetBuf()
{
return m_szBuf;
};
};
void fun()
{
AutoNewDel tmpObj(100);
char* p= tmpObj.GetBuf();
strcpy(p,"one world, one dream");
cout<<p<<endl;
AutoNewDel tmpObj2=tmpObj;
cout<<"tmpObj2.m_szBuf = "<<tmpObj2.GetBuf()<<endl;
}
int main()
{
fun();
cout<<"exit main"<<endl;
return 0;
}
#include <cstring>
using namespace std;
class AutoNewDel
{
// Attribute
private:
char* m_szBuf;
unsigned int m_nSize;
int * m_count; //新增加的语句
public:
AutoNewDel(unsigned int n=1)//在构造函数中申请内存
{
m_szBuf=new char[n];
m_nSize=n;
//新增加的语句
m_count=new int;
*m_count=1;
cout<<"count is : "<<*m_count<<endl;
};
//新增加的复制构造函数
AutoNewDel(const AutoNewDel & s)
{
m_nSize=s.m_nSize;
m_szBuf=s.m_szBuf;
m_count=s.m_count;
(*m_count)++;
cout<<"count is : "<<*m_count<<endl;
}
~AutoNewDel()
{
(*m_count)--;
cout<<"count is : "<<*m_count<<endl;//新增加的两条语句
if(*m_count==0)
{
cout<<"buf is deleted"<<endl;
if(m_szBuf!=NULL) //提供安全机制
{
delete[] m_szBuf; //删除字符数组
m_szBuf=NULL; //防止出现野指针
if(m_count!=NULL)
{
delete m_count;
m_count=NULL;
}
}
}
};
char* GetBuf()
{
return m_szBuf;
};
};
void fun()
{
AutoNewDel tmpObj(100);
char* p= tmpObj.GetBuf();
strcpy(p,"one world, one dream");
cout<<p<<endl;
AutoNewDel tmpObj2=tmpObj;
cout<<"tmpObj2.m_szBuf = "<<tmpObj2.GetBuf()<<endl;
}
int main()
{
fun();
cout<<"exit main"<<endl;
return 0;
}
程序输出结果如下:
想要获得更多内容,可点击:《Visuanl C++代码参考与技巧大全》学习笔记——索引随笔
0 0
- 避免内存泄露的方法
- 避免内存泄露的方法
- 避免内存泄露的方法
- 避免内存泄露的方法
- Android应用程序避免Context相关的内存泄露的方法
- Android编程中避免内存泄露的方法总结
- 4种JavaScript的内存泄露及避免方法
- Java内存泄露及避免方法
- Java 内存泄露以及避免方法
- 避免Drawable保持引用的内存泄露
- 避免引用Context造成的内存泄露
- (四)避免对象的内存泄露
- 良好的编程习惯避免内存泄露
- 避免浏览器内存泄露
- 避免内存泄露
- 避免内存泄露
- 避免内存泄露
- 避免内存泄露
- GRE写作必备句型
- python 编码问题——字符编码
- ISO 8859(GBK) 编码文件转码到UTF-8编码文件
- JQuery 提供了两种方式来阻止事件冒泡及区别
- 黑马程序员--内部类
- 避免内存泄露的方法
- Permutation Sequence
- 黑马程序员 异常( 格式 体现 总结 ) 包
- javascript 原生态 checkbox 操作
- 修改cas-server(二),修改认证方式为jdbc。
- 关于安卓sdk的下载
- 将数组b合并到数组a中
- 融云即时通讯集成总结
- 编写auto_ptr感