Effective C++:条款08:别让异常逃离析构函数!

(一)先看下面的代码:

class Widget {
public:
	...;
	~Widget();
};

void doSomething() {
	vector<Widget> v;
}

如果析构函数会抛出异常,当doSomething函数结束的时候,会调用n次Widget的析构函数,每次都抛出异常的话,程序会过早结束或出现不明确的行为!

也就是说:当我们的析构函数必须执行一个动作!而该动作可能会在失败时抛出异常。

所以必须要解决!再看下面的代码:

<pre class="cpp" name="code">class DBConnection {
public:
	...;
	static DBConnection create();
	void close();
};

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

DBConn dbc(DBConnection::creat());
 

如果dbc对象被析构的时候,db.close();发出异常的话,那就会造成麻烦!有两种解决办法,第一种是抛出异常的时候利用abort()来强迫结束程序!第二种是吞下因调用close()而发出的异常!但是这两种方法都不是很好的方法!

//第一种方法:
DBCon::~DBCon() {    
	try{
		db.close();
	}catch(...) {    
		制作运转记录,记下调用异常   
			std::abort();   
	}  
};
//第二种方法:
DBCon::~DBCon() {   
	try{
		db.close();
	}catch(...) {   
		制作运转记录,记下调用异常   
	}
};

但是我们有更好的方法来解决这个问题。因为当析构函数抛出异常时,时间确实太晚了,我们希望尽量早的发现异常,这样及早发现问题,让我们有时间来解决。一个较佳的策略是重新设计DBCon借口,提供一个接口让用户可以先手动的去调用可能发生异常的函数,具体代码如下:

<pre class="cpp" name="code">class DBConnection {
public:
	...;
	static DBConnection create();
	void close();
};

class DBConn {
public:
	void close() {         //设置给用户的函数!用户必须主动调用,虽然客户不一定要来调用这个函数,但是至少我们给了他这样的机会
		db.close();
		closed = true;
	}
	~DBConn() {
		if(!closed) {
			try {
				db.close();
			}
			catch(...) {
				制作运转记录,记下对close的调用失败;
			}
		}
	}
private:
	DBConnection db;
	bool closed;
};

DBConn dbc(DBConnection::creat());

 

把调用close的责任从DBCon析构函数的手上转移到了用户手中,这样就给客户及早的发现异常提供了机会,虽然客户不一定要去调用,但是至少我们给了他这样的机会。

 

 

 

请记住:

(1)析构函数绝对不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下他们(不传播)或结束程序。

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

 



 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值