第三章,异常

条款11 禁止异常流出destructor之外

描述

(1)一个对象调用析构函数只有两种情况,一个是对象正常状况下销毁时调用,另一种情况是当函数中抛出异常且该异常没有在当前函数内被捕获时,C++ 会启动栈展开过程————从抛出异常的函数开始,逐层回退调用栈,销毁每一层栈上的局部对象(自动对象),直到找到能处理该异常的catch块;如果最终没找到,程序会调用std::terminate终止。

(2)在栈展开(异常传播)过程中,如果析构函数抛出了未被处理的新异常,程序会立即调用std::terminate终止运行。

(3)防止异常流出destructor,确保其完成了所有应该完成的任务。

//不建议的原始写法:
~DangerousObj() {
cout << "❌ 析构:" << name << " 开始执行,准备抛异常..." << endl;
// 析构中抛出新异常(未被本地捕获)
throw runtime_error(name + " 析构时抛出的异常");

// 注意:下面的代码永远不会执行,析构直接中断
cout << "析构:" << name << " 执行完毕" << endl;
}

//强烈建议的写法:
~DangerousObj() {
cout << "❌ 析构:" << name << " 开始执行,准备抛异常..." << endl;
try {
// 可能抛异常的操作放在try块内
throw runtime_error(name + " 析构时抛出的异常");
} catch (const exception& e) {
// 捕获并处理异常(比如记录日志),不向外传播
cerr << "⚠️ 析构内捕获异常:" << e.what() << endl;
}
// 析构可以正常完成
cout << "析构:" << name << " 执行完毕" << endl;
}