异常安全是指代码在发生异常时不会造成资源泄漏或状态不一致。基本保证(basic guarantee)指异常后程序状态有效且无泄漏,实现方式包括使用raii和推迟变更;强保证(strong guarantee)要求异常后状态与调用前完全一致,常用“复制并交换”模式实现;不抛出保证(nothrow guarantee)确保函数绝不抛异常,适用于析构函数、swap等关键操作,通常最难实现。

在C++开发中,异常安全是一个常被提到的话题。很多人会问“怎么保证异常安全?”其实关键在于理解不同级别的异常安全保证:基本保证、强保证和不抛出保证。这三者不是简单的写法差异,而是对程序稳定性和容错能力的不同要求。

什么是异常安全?
异常安全是指代码在发生异常时,不会造成资源泄漏、数据损坏或状态不一致的问题。换句话说,即使函数中途抛出了异常,整个程序的状态仍然应该是合法的、可恢复的。
基本保证(Basic Guarantee)
基本保证是最基础的一层。它意味着如果函数执行过程中抛出了异常,程序的状态虽然可能改变,但对象仍然是有效的,没有资源泄漏,也没有未定义行为。
立即学习“C++免费学习笔记(深入)”;

常见场景:
- 插入元素到容器时抛出异常
- 文件操作中部分写入失败
建议做法:

- 使用RAII(资源获取即初始化)管理资源,比如用
std::unique_ptr而不是裸指针。 - 在修改对象前先复制一份原始数据,这样一旦异常发生可以回滚。
- 避免直接修改原始数据,尽量推迟变更直到确定不会抛出异常。
举个例子,如果你往一个vector里push_back一个元素,而这个元素的拷贝构造可能会抛异常,那vector应该保持原来的样子或者至少是有效状态,不能崩溃也不能内存泄漏。
强保证(Strong Guarantee)
强保证比基本保证更严格。它要求如果函数抛出异常,程序状态必须和调用之前完全一样,就像什么都没发生过一样。
适用情况:
- 涉及事务性操作,比如数据库更新
- 修改多个对象且必须全部成功或全部失败的操作
实现技巧:
- 使用“复制并交换”模式(Copy and Swap)
- 先构建新状态,确认无误后再替换旧状态
- 把可能抛异常的操作提前做,确保后面的操作不会失败
比如你实现一个赋值运算符,你可以先拷贝传入的对象,然后交换内部数据。这样即使拷贝过程中抛了异常,原对象的状态还是不变的。
不抛出保证(Nothrow Guarantee)
这是最高级别也是最难做到的保证。它要求函数绝对不会抛出异常,适用于那些不允许失败的关键路径。
应用场景:
- 析构函数(你不希望析构时崩溃)
- swap函数(标准库很多地方依赖swap不抛异常)
- 移动构造函数/移动赋值运算符(为了性能和稳定性)
注意事项:
- 确保调用的所有函数也都有nothrow保证
- 避免使用可能抛异常的操作,比如new(除非用了nothrow版本)
- 使用标准库中标记为noexcept的函数
例如,标准库中的std::vector::swap通常是noexcept的,因为它只是交换内部指针,不会分配内存也不会抛异常。
总结一下区别:
| 异常安全级别 | 行为描述 | 实现难度 |
|---|---|---|
| 基本保证 | 异常后状态有效,可能有副作用 | 中等 |
| 强保证 | 异常后状态与调用前一致 | 较高 |
| 不抛出保证 | 函数绝不会抛异常 | 最高 |
实际开发中,没必要所有代码都追求强保证或noexcept,要根据具体场景权衡。比如底层库函数、核心逻辑模块更适合提供强保证;而像日志记录、非关键功能则可以接受基本保证。
基本上就这些。










