條款 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;
}