effective c++阅读之旅---条款8

条款8:别让异常逃离析构函数

c++并不禁止析构函数抛出异常,但并不鼓励这样做。

考虑如下代码:

class Widget
{
public:
	//...
	~Widget() {} //假设可能会抛出异常
};

void doSomething()
{
	std::vector<Widget> v;
	//...
}

分析:
当v析构的时候,必须销毁其中的所有的Widgets对象。假设v含有10个Widget,而在析构第一个元素的时候,抛出一个异常。其他九个还是应该被销毁,因此v又调用它们各个析构函数,但若是第二个Widget析构又出现异常,现在有两个同时作用的异常,程序不是强制结束就是导致不明确。因此很有可能出现内存泄漏!

但如果我们现在有这个需求,析构函数必须要执行某个动作,而该动作又可能会失败,失败需要抛出异常,那怎么办呢?

举个例子:

使用该类负责数据库连接

class DBConnection
{
public:
	//...
	static DBConnection create();
	void close();//关闭连接,失败抛出异常!
};

为了确保客户不忘记在DBConnection 对象身上调用close(),我们又创建一个用来管理DBConnection 资源的class,并在它的析构中调用close。

class DBConn
{
public:
	//...
	~DBConn()
	{
		db.close();
	}
private:
	DBConnection db;
};

于是客户写出了这样的代码!

//创建DBConnection对象,并且交给DBConn对象便于管理!
DBConn dbc(DBConnection::create());

我们发现只要调用close成功,一切安好!但是如果抛出异常,则会导致一系列问题!

两个办法:

1、抛出异常,结束进程

~DBConn()
{
	try { db.close(); }
	catch (...)
	{
		//制作记录,记下该失败!
		std::abort();
	}
}

2、抛出异常,吞下,记录相应异常,让程序继续运行

~DBConn()
{
	try { db.close(); }
	catch (...)
	{
		//制作记录,记下该失败!
	}
}

但这些办法,都没啥吸引力。问题在于都无法对"导致close抛出异常"的情况主动做出反应。

**一个更好的策略:
重新设计DBConn接口,让客户自己有机会可能对问题作出反应!
例如:DBConn提供public的close函数,赋予客户一个机会自己处理该异常,通过一个bool的标志,在析构判断外部是否主动调用关闭,没有调用,自己进行调用!
不过,如果DBConnection析构函数调用close失败,我们又退回了之前要么吞下要么退出的老路!!!

class DBConn
{
public:
	//...
	void close()
	{
		db.close();
		closed = true;
	}
	~DBConn()
	{
		if (!closed)
		{
			try { db.close(); } //如果客户没自己关闭,这边析构也会关闭!
			catch (...)
			{
				//制作记录,记下该失败!
			}
		}		
	}
private:
	DBConnection db;
	bool closed; //增加一个标志判断,客户是否自己主动调用关闭!!!
};

总结:

  • 析构函数尽可能不要抛出异常。如果析构中调用的函数又很有可能抛出异常,则应该捕捉该异常,然后吞下或者终止程序!
  • 如果客户需要对某个函数运行期间的抛出异常做出反应,那么class中应该提供一个普通函数执行该操作!

结尾: 我是航行的小土豆,喜欢我的程序猿朋友们,欢迎点赞+关注哦!希望大家多多支持我哦!有相关不懂问题,可以留言一起探讨哦!

如有引用或转载记得标注哦!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值