Effective C++ Term 8 别让异常逃离析构函数
2019-05-17 本文已影响0人
vancymoon
析构函数往往身肩销毁资源等一些十分重要的责任,但如果析构函数在销毁资源的过程中吐出了一个异常,它就没有办法继续正常地执行它的任务,会造成资源泄漏等等严重的后果,所以我们不能够让异常逃离析构函数,至少要在析构函数遇到异常的时候能够终止程序,或者让它吞下异常
比如我们有一个vector<MyClass> v_myclass
,当v_myclass
被销毁时,它会依次调用每个元素的析构函数,如果在销毁第一个、第二个、第三个……元素时,~MyClass()
都吐出了异常,那么程序将会因为接收到太多异常而出现未定义行为,所以最好是不要让~MyClass()
吐出异常,比如我们可以这样做
~MyClass::MyClass() {
try {
// 销毁资源
} catch {
abort(); // 直接结束程序
}
}
或者
~MyClass::MyClass() {
try {
// 销毁资源
} catch {
log_err(); // 默默吞下异常
}
}
当然,稳妥起见,直接停止运行会保证程序不出现未定义行为;吞下异常意味着要承担一定风险
由于直接在析构函数进行销毁资源,用户是无法去捕捉到析构函数中的异常的,他们也不知道何时析构函数会被调用,因此不妨留出一个“销毁资源”接口,在析构函数中,我们照常销毁资源,以防用户没有自己销毁资源;同时也给用户一定自由,让他们可以自己去销毁资源,并处理销毁资源步骤失败的情况,如
class Database {
public:
void close() {
// do something to close the DB
closed = true;
}
~Database() {
if (!closed) {
try{
close();
} catch {
// log error
// ...
}
}
}
private:
bool closed = false;
};
这里,我们为用户提供了手动close
的机会,同时会在析构函数中再次检查数据库是否关闭,如果未关闭,我们还是会以之前介绍过的方式进行资源的销毁,并避免异常逃离析构函数