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

问题:如果一个类的析构函数必须执行一个动作,而该动作可能会在失败时抛出异常,该怎么办?举个例子,假设使用过一个class负责数据库连接:

class DBConnection
{
public:
	...
	static DBConnection create();	//此函数返回DBConnection对象

	void close();			//关闭联机;失败则抛出异常
};

一个较佳策略是创建一个用来管理DBConnection资源的DBConn类,DBConn类自己提供一个close函数,因而赋予客户一个机会得益处理“因该操作而发生的异常”。DBConn也可以追踪其所管理的DBConnection是否已被关闭,若没有被关闭,则由DBConn的析构函数关闭它。这可防止遗失数据连接。然而如果DBConnection析构函数调用close失败,则可使用“强制结束程序”或“吞下异常”的方法:

class DBConn
{
public:
	DBConn();
	~DBConn();

	void close();
private:
	DBConnection db;
	bool closed;
};

DBConn::DBConn()
{
}

DBConn::~DBConn()
{
	if(!closed)
	{
		try
		{
			db.close();          //关闭连接
		}
		catch(...)                //如果关闭动作失败
		{
			写日志,记下对close的调用失败;  //记录下来并结束程序
			...                //或者吞下异常;
		}
	}
}

void DBConn::close()		//供客户使用的新函数
{
	db.close();
	closed = true;
}

  

如果某个操作可能在失败时抛出异常,而又存在某种需要必须处理该异常,那么这个异常必须来自析构函数以外的某个函数。因为析构函数抛出异常及时危险,总会带来“过早结束程序”或“发生不明确行为”的风险。

请牢记:

1、析构函数绝对不要抛出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕获异常,然后吞下它们或结束程序。

2、如果客户需要对某个操作函数进行运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行操作。

 

posted @ 2013-12-10 22:12  陌上归人  阅读(374)  评论(0编辑  收藏  举报