条款 08:别让异常逃离析构函数
Prevent exceptions from leaving destructors.
如果析构函数吐出异常,可能导致不明确行为,如下面 vector 销毁时会调用所有元素的析构函数,这会导致不明确行为
class A {
...
~A() {...} // 假设析构函数会吐出异常
};
void f() {
std::vector<A> v;
...
}
关闭资源时经常会遇到类似问题,如处理数据库连接时为了方便做封装,就可能导致析构吐出异常
class DBConnection {
public:
static DBConnection create();
void close();
}
class DBManager {
public:
...
~DBManager() {
db.close(); // 可能有异常逃离析构
}
private:
DBConnection db;
}
{
DBManager db(DBConnection::create());
}
方法一:明确终止或吞掉异常
~DBManager() {
try { db.close(); }
catch (...) {
log();
std::abort(); // 明确终止
}
}
~DBManager() {
try { db.close(); }
catch (...) {
log(); // 直接吞掉异常
}
}
方法二:将析构函数中可能吐出异常的操作提取到普通函数,给用户自行处理异常的机会
class DBManager {
public:
...
~DBManager() {
if (!closed) {
try {
db.close();
}
catch (...) {
log();
}
}
}
void close() // 由客户显式调用,自行处理异常
{
db.close();
closed = true;
}
private:
DBConnection db;
bool closed;
}