C++异常处理应优先使用const&捕获、析构函数禁抛异常、依赖RAII而非try-catch、避免误用uncaught_exception。

catch 里别用值传递捕获异常对象
直接拷贝异常对象可能触发额外构造/析构,甚至引发新异常。更糟的是,如果基类 catch 按值接收,派生类异常会被切片,丢失类型信息和成员数据。
- 一律用
const&捕获:比如catch (const std::exception& e) - 自定义异常类确保拷贝构造函数不抛异常(标记
noexcept) - 避免
catch (std::exception e)或catch (MyError e)这类写法
不要在析构函数里 throw 异常
C++ 标准规定:析构函数默认是 noexcept(true),一旦抛出未捕获异常,程序直接调用 std::terminate() —— 不会栈展开,不会执行后续析构,静默崩溃。
- 析构函数内所有可能抛异常的操作必须用
try-catch吞掉或转为日志 - 像
std::ofstream::close()这种可能失败的调用,要检查fail()而非依赖异常 - 若真需报告错误,改用返回状态码或发信号,别 throw
std::terminate 和 uncaught_exception 的实际意义很有限
std::set_terminate() 看似能兜底,但发生时往往已无法安全恢复;std::uncaught_exception() 在 C++17 起已被弃用,因为它的行为在栈展开中途不可靠。
- 别指望
std::set_terminate做清理工作——此时栈已停止展开,this、局部变量、RAII 对象都不可靠 - 需要“有异常时做某事”,应使用
std::uncaught_exceptions()(C++17 新版,返回当前未处理异常数量) - 常见误用:在 RAII 析构里靠
uncaught_exception()判断是否回滚事务——它在异常传播中可能返回 false,导致漏处理
资源管理比 try-catch 更重要
很多人一上来就堆 try-catch,结果逻辑分散、重复清理、掩盖设计缺陷。C++ 的异常安全核心其实是 RAII,不是 catch。
立即学习“C++免费学习笔记(深入)”;
- 优先用
std::unique_ptr、std::lock_guard、std::fstream等自动管理资源,而不是在catch里手动delete或close() - 函数接口设计上,明确哪些函数可能 throw(加注释或文档),调用方按需处理,不是每个函数都套一层
try - 日志、监控、超时等非核心路径错误,考虑用
std::optional或错误码返回,避免异常开销和传播不确定性
异常机制本身没问题,问题常出在把异常当控制流、绕过资源生命周期管理、或者在不允许抛异常的地方硬 throw —— 这些地方比怎么写 catch 更容易出事。










