10 在构造函数防止资源泄漏

2021/8/19 23:07:23

本文主要是介绍10 在构造函数防止资源泄漏,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

有以下构造函数和析构函数:

BookEntry::BookEntry()
: pImage(nullptr)
, pClip(nullptr)
{
    pImage = new Image();
    pClip = new Clip();
}
~BookEntry()
{
    delete pImage;
    delete pClip;
}

构造函数在初始化列表将指针pImagepClip置空,然后在函数内为指针初始化对象。在析构函数释放指针的资源,避免内存泄漏。

在正常情况下运行良好,但当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对象中可能泄漏的资源,它的构造函数需要用同样的方法进行清除:构造函数在异常传递之前完成必要的清除工作。

pImagepClip是常量指针,必须要成员初始化列表完成构造,上述的方法不再适用。同时,初始化列表只允许表达式,trycatch必须转移到别的地方。

  1. 在成员函数中完成初始化
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;
    }
}
  1. 把对象指针作为一个资源,被一个局部对象管理,如智能指针。
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 在构造函数防止资源泄漏的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程