您的位置:首页 > 其它

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

2009-06-08 09:38 309 查看
条款08:别让异常逃离析构函数
(Prevent exception from leaving destructors).

内容:
一般而言,只要析构函数抛出异常,程序就会可能过早结束或出现不确定行为,C++不喜欢析构函数吐
出异常!!那么我们如何避免呢?书上举的一个例子是:假设你使用一个class负责数据库连接:
class DBConnection{
public:
...
static DBConnection create(); //get a DBConnection omit parameter for simplicity
void close(); //close DBConnection
};
为了防止客户使用完DBConnection以后忘记调用close(),我们可以创建一个新类DBConn来管理这个
对象,我们可以在这个新类的析构函数中调用该DBConnection对象的close();
class DBConn{
public:
DBConn(DBConnection& db):db_(db){}
~DBConn(){
db_.close();
}
...
private:
DBConnection& db_;
};
我们就可以这样来用它:
{
DBConn connection(*(DBConnection.create()));
... //自动析构时候调用close方法
}
这里出现个问题就是如果db_.close();要是吐出异常怎么办?通常我们用以下解决方案:
一是只要抛出异常就结束程序:
DBConn::~DBConn(){
try{
db_.close();
}catch(...){
....
std::abort();//结束程序,可以强制"不明确行为"死掉
}
}
二是吞掉异常:
DBConn::~DBConn(){
try{
db_.close();
}catch(...){
...
}
}
一般而言吞掉异常不是很好的处理发式,但总比为"粗暴的结束程序"或"出现不明确行为"担负代价和风险
要好,这样即使程序遭遇了一个错误或者异常情况下都可以继续运行,在另一方面提高了软件的健状性.
而这些解决方案都存在一个问题:客户不能对"close失败的异常情况"做出反应.为了解决这个问题,这里
我们可以将独立出来一个新的close接口:
class DBConn{
public:
DBConn(DBConnection& db):db_(db){}
void close(){
db_.close();
isClosed_ = true;
}
~DBConn(){
if(!isClosed_){
//使用以上两种解决方案之一来进行解决.
}
}
...
private:
DBConnection& db_;
bool isClosed_;
};
这样我们来重新审理这段代码,一个新的接口close(),提供给客户调用,如果出现异常客户可以第一
时间来进行处理,如果可以确定这里不会出现异常的话,也可以不处理,客户还可以选择不调用close(),
放弃对可能出现的异常处理,选择让析构函数自动调用.这样的设计你不觉得更加的合理吗?呵呵

请记住:
▲ 析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉异
常,然后吞下它们(不传播)或结束程序.
▲ 如果,客户需要对某个操作函数运行期间的异常做出反应,那么class应该提供一个普通函数(而非
在析构函数中)执行该操作.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: