Effective C++ (学习笔记详解08)
程序员文章站
2022-06-08 10:20:36
...
假期学习使我快乐哈哈哈~加油啊小朋友痛并快乐着!!
08:别让异常逃离析构函数
如果析构函数必须执行一个动作,而该动作可能会在失败时抛出异常,例如
class DBConn{ //class 用来管理DBConnetive对象
public:
~DBConn(){ //确保db总能被关闭。但是一旦调用产生异常,析构函数就会传播该异常
db.close();
}
private:
DBConnetive db;
};
两个办法避免该问题。DBConn
的析构函数可以:
1、如果close抛出异常就结束程序。通常通过调用abort
完成:
DBConn::~DBConn
{
tr{ db.close(); }
catch(...)
{
//记下close调用失败
std::abort();
}
}
如果程序遭遇一个“于析构期间发生的错误”后无法继续执行,“强迫结束程序”是个合理选项。毕竟它可以阻止异常从析构函数传播出去(那会导致不明确的行为)。也就是说调用abort
可以抢先制“不明确行为”于死地。
2、吞下因调用close
而发生的异常
DBConn::~DBConn
{
try{ db.close(); }
catch(...)
{
//记下close调用失败
}
}
一般而言,将异常吞掉是个坏主意,因为它压制了“某些动作失败”的重要信息!然而有时候吞下异常也比负担“草率结束程序”或“不明确行为带来的风险”好。为了让这成为一个可行方案,程序必须能够继续可靠地执行,即使在遭遇并忽略个错误之后。
以上两种做法都无法对“导致close
抛出的异常”做出反应。
**解决办法:重新设计DBConn
接口,使其客户有机会对可能出现的问题作出反应。
class DBConn{
public:
void close(){ //供使用的新函数
db.close();
closed = true;
}
~DBConn(){
if( !closed ){
try{db.close(); } //关闭连接
catch(...){ //记下close调用失败 }
}
}
private:
bool closed;
};
- 不要让析构函数抛出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,并不让他们继续传播(吞下他们或结束程序)。
- 如果需要对某个操作函数运行期抛出的异常做回应,则
class
应提供一个普通函数(而非在析构函数中)执行该操作。