析构函数可以抛出异常吗?为什么不能抛出异常?除了资源泄露,还有其他需考虑的因素吗?

发布时间:2026/10/18 6:21:04
析构函数可以抛出异常吗?为什么不能抛出异常?除了资源泄露,还有其他需考虑的因素吗? 在我们不做过多处理的情况下析构函数是绝对不能抛出异常的这会直接导致我们的整个程序被强制终止现象#include iostream #include stdexcept using namespace std; ​ class Bad { public: ~Bad() { // C11起默认 noexcept cout ~Bad: 准备抛异常\n; throw runtime_error(析构里抛的异常); } }; ​ int main() { try { Bad a; // a 离开作用域析构 } catch (const exception e) { cout 捕获到: e.what() \n; } cout main 正常结束\n; // 这行不会执行 }C关于异常处理的两点规则在栈展开过程中如果析构函数抛出异常且当前已有未捕获异常会直接调用std::terminate。析构函数默认隐式noexcept只要它内部抛出异常无论当前有没有其他异常都会直接调用std::terminate。class Bad2 { public: ~Bad2() noexcept(false) { // 显式声明可能抛 throw runtime_error(析构异常); } };我们可以通过显式指定noexcept(false)的方式去告诉编译器我们这个析构函数可以抛出异常这样就会被成功地捕获到class Leaky { FILE* f; public: Leaky() { fopen_s(f, a.cpp, w); } ~Leaky() noexcept(false) { cout ~Leaky: 准备抛异常\n; // ① 清理 throw runtime_error(boom); // ② 抛出析构后面的逻辑全跳过 cout 这行永远不执行\n; // 演示用 fclose(f); } };不过我们在实际的编程中也不建议去显式的指定析构函数可以抛异常也不建议去让它抛异常因为这很可能导致一些资源的泄露。比如上面这个代码在抛出异常之后异常后面的代码是永远不会被执行的如果后面是会去释放一些大量资源这就会导致内存泄漏真正致命的——栈展开时再抛class Bad2 { public: ~Bad2() noexcept(false) { cout ~Bad2 析构再抛一个\n; throw runtime_error(析构异常2); } }; ​ void foo() { Bad2 a; throw runtime_error(原始异常); // 触发栈展开 → a析构 → 再抛 } ​ int main() { try { foo(); } catch (const exception e) { cout 抓到: e.what() \n; } }正确做法class Good { public: ~Good() noexcept { try { cleanup(); // 可能失败的操作 } catch (...) { // 吞掉记日志别让它跑出去 cerr 析构清理失败已忽略\n; } } void cleanup(); // 用户可以显式调用并处理错误 ​ // 进阶提供 close()让用户主动调用、主动 catch void close() { /* 真正可能失败的清理 */ } };析构里try-catch(...)吞掉所有异常如果清理真的可能失败且用户该知道就提供close()让用户显式调用。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询