不崩溃的系统级C++代码关键在于异常发生时资源不泄漏、对象可析构、状态可回退;必须遵循RAII、析构函数声明noexcept、赋值采用copy-and-swap,且每种资源需专属noexcept管理类。
写出不崩溃的系统级 C++ 代码,关键不是“避免抛异常”,而是让每次异常发生时——资源不泄漏、对象可析构、状态可回退。Core Guidelines 明确要求:所有资源管理必须基于 RAII,所有析构函数必须 noexcept,所有强保证操作优先用 copy-and-swap。
noexcept?栈展开(stack unwinding)期间若析构函数意外抛出异常,C++ 标准强制调用 std::terminate() —— 程序直接终止,毫无回旋余地。这不是理论风险,而是真实 crash 的常见源头。
~MyClass() noexcept,哪怕它只调用 fclose() 或 delete
std::ofstream::close() 可能抛 std::ios_base::failure;改用 std::ofstream::close() + 检查 failbit)std::lock_guard 的析构函数均已标记 noexcept,可放心依赖operator= 怎么写才真正强异常安全?裸写赋值运算符极易破坏强保证:比如先 delete[] data 再 new,中间抛异常就导致悬空指针或内存泄漏。Core Guidelines 推荐唯一可靠模式:copy-and-swap。
class Buffer {
std::unique_ptr data_;
size_t size_;
public:
Buffer& operator=(Buffer other) noexcept { // 注意:参数传值,自动拷贝
swap(*this, other); // swap 是 noexcept 的
return *this;
}
friend void swap(Buffer& a, Buffer& b) noexcept {
using std::swap;
swap(a.data_, b.data_);
swap(a.size_, b.size_);
}
};
Buffer other),触发拷贝构造——失败则原对象完全不受影响swap 必须是 noexcept,且只交换指针/整数等基础成员,不涉及内存分配other 在函数退出时自动析构很多团队误以为用了 std::unique_ptr 就算 RAII 完成,结果遇到文件句柄、POSIX 信号量、GPU buffer、自定义锁等非内存资源时仍泄漏。Core Guidelines 强调:RAII 是接口契约,不是语法糖。
int fd、pthread_mutex_t*),必须封装为独立类,构造获取、析构释放= delete),移动构造/赋值必须 noexcept
std::fstream 那样,在析构时静默关闭,不抛异常最常被忽略的一点:异常安全不是靠“catch 住所有异常”来实现的,而是靠资源绑定到作用域、状态变更延后到无异常操作、以及严格限制 noexcept 边界。一旦在析构或 swap 中出现未声明的异常,系统级稳定性就已实质崩塌——而这种问题往往在压力测试或日志关闭时才暴露。