noexcept 是编译期承诺函数绝不抛异常,strong exception safety 是运行期保证操作失败时状态回滚到调用前;二者共同确保对象始终有效、可析构、不泄漏。

什么是 noexcept 和 strong exception-safe,它们解决什么问题
C++ 的异常安全不是“有没有 try-catch”,而是对象在异常中途抛出时,是否仍处于有效、可析构、不泄漏的状态。noexcept 是编译期承诺——函数绝不会向外传播异常;strong exception safety 是运行期保证——操作失败时,状态回滚到调用前(要么全成功,要么像没发生过)。两者目标一致:让调用者能放心依赖资源生命周期和对象一致性。
-
noexcept不是性能优化开关,它是接口契约:违反它会直接调用std::terminate - strong guarantee 通常靠“copy-and-swap”或“prepare-then-commit”实现,不是靠 catch 所有异常
- weak guarantee(仅保证对象仍可析构)是底线,但很多标准容器操作(如
std::vector::push_back)在分配失败时只提供 basic guarantee
怎么写真正 noexcept 的函数:别信声明,要查实现
noexcept 声明本身不阻止 throw,它只是告诉编译器“我保证不抛”。一旦函数体内调用了可能抛异常的代码(比如 std::string 构造、new、非 noexcept 成员函数),就违背契约。
- 所有被调用的函数必须也是
noexcept(包括构造、赋值、析构);std::vector的移动构造是noexcept,但拷贝构造不是 - 析构函数默认是
noexcept(true),显式写~T() noexcept更清晰;若析构里调了可能 throw 的代码,必须用noexcept(false)并确保不 throw - 使用
noexcept运算符检查:noexcept(obj.func())返回bool编译期常量,可用于 SFINAE 或 static_assert - 示例:安全的移动赋值运算符
T& operator=(T&& other) noexcept { if (this != &other) { delete[] data_; data_ = other.data_; size_ = other.size_; other.data_ = nullptr; other.size_ = 0; } return *this; }
实现 strong exception safety:swap 是最可靠手段
强异常安全最难的地方不是“怎么捕获异常”,而是“怎么确保中间状态可逆”。swap 之所以可靠,是因为它通常只交换指针/整数(基本类型操作),天然 noexcept,且交换前后两个对象都处于有效状态。
- 不要用“先改局部状态,再更新成员”的顺序;正确做法是:新资源准备好 → 原状态暂存 → 原子交换 → 清理旧资源
-
std::vector::assign、std::string::assign等标准库实现都基于 copy-and-swap 或类似模式 - 自定义类中,优先实现
swap非成员函数(ADL 友好),并标记为noexcept - 示例:强异常安全的赋值运算符
T& operator=(const T& other) { T tmp(other); // 可能 throw,但不影响 *this swap(*this, tmp); // guaranteed noexcept return *this; }
容易被忽略的坑:析构函数、内存分配、标准容器行为
很多人以为“只要自己没写 throw 就安全”,其实大量隐式调用藏在底层。
立即学习“C++免费学习笔记(深入)”;
-
std::make_unique和new可能抛std::bad_alloc,除非你用new(std::nothrow)并检查返回值 - 类型的析构函数若抛异常(哪怕只是
std::cout << "dtor"时 IO 失败),会导致栈展开中断,程序终止——所以析构函数里不要做可能失败的操作 -
std::vector::reserve不提供 strong guarantee:分配失败时,原 vector 保持不变(basic),但 capacity 可能未变;而resize在增长时若分配失败,也只保证 basic - 移动操作看似高效,但若移动构造函数没声明
noexcept,std::vector在扩容时会退化为拷贝(因为无法保证强异常安全)
异常安全不是加几个 try 就完事,它要求你清楚每个函数的异常规范、每块内存的归属权、以及 swap 是否真的原子。最麻烦的从来不是写 throw,而是写那个“永远不 throw”的析构和 swap。


















