10 在构造函数防止资源泄漏
作者:互联网
有以下构造函数和析构函数:
BookEntry::BookEntry()
: pImage(nullptr)
, pClip(nullptr)
{
pImage = new Image();
pClip = new Clip();
}
~BookEntry()
{
delete pImage;
delete pClip;
}
构造函数在初始化列表将指针pImage
、pClip
置空,然后在函数内为指针初始化对象。在析构函数释放指针的资源,避免内存泄漏。
在正常情况下运行良好,但当pClip = new Clip();
这一步发生错误时,异常将会被BookEntry构造函数
的调用者。错误的原因可能是operator new
不能分配足够的内存,或是Clip
的构造函数发生异常。
__发生异常的BookEntry
对象并没有完成构造。C++仅能删除被完全构造的对象,即构造函数完全运行完毕,因此~BookEntry()
永久不会被调用,导致了内存泄漏。__如果尝试主动捕获异常并调用析构函数:
try
{
BookEntry * obj = new BookEntry();
}
catch(...)
{
delete obj;
throw;
}
__new
首先通过operator new
分配堆内存,然后调用相应的构造函数,最后将内存首地址返回到指针。当BookEntry
的构造函数发生异常时,obj
仍然是空指针,delete obj
并不能释放掉已分配的堆内存。__因此对象必须在构造函数发生异常时,在构造函数内执行必要的清除工作。
BookEntry::BookEntry()
: pImage(nullptr)
, pClip(nullptr)
{
try
{
pImage = new Image();
pClip = new Clip();
}
catch(...)
{
delete pImage;//删除空指针是安全的
delete pClip;
throw;
}
}
如果是Clip
的构造函数发生异常,构造函数能够将已分配内存的pImage
资源释放,但对于Clip
对象中可能泄漏的资源,它的构造函数需要用同样的方法进行清除:构造函数在异常传递之前完成必要的清除工作。
当pImage
和pClip
是常量指针,必须要成员初始化列表完成构造,上述的方法不再适用。同时,初始化列表只允许表达式,try
和catch
必须转移到别的地方。
- 在成员函数中完成初始化
BookEntry::BookEntry()
: pImage(initImage())//通过私有构造函数初始化对象
, pClip(initClip())
{}
Image * BookEntry::initImage()
{
return new Image();
}
Clip * BookEntry::initClip()
{
try
{
return new Clip();
}
catch(...)
{//因为`Clip`在`pImage`之后构造,其初始化函数负责释放`pImage`资源。
delete pImage;
}
}
- 把对象指针作为一个资源,被一个局部对象管理,如智能指针。
class BookEntry
{
public:
BookEntry();
~BookEntry() = default;//资源自动释放
private:
const auto_ptr<Image> pImage;
const auto_ptr<Clip> pClip;
}
BookEntry::BookEntry()
: pImage(new Image)
, pClip(new Clip)
{}
通过智能指针简化构造函数中的异常处理:当new Clip
发生异常时,智能指针pImage
是已经完全构造的局部对象,在离开生命周期后会自动释放掉,因此不需要再手动捕获异常来进行清除。同时由局部对象管理动态资源,省略了析构函数中的清除操作。
标签:10,Clip,泄漏,BookEntry,pClip,new,pImage,构造函数 来源: https://www.cnblogs.com/sandersunkown/p/15163903.html