nothrow保证即noexcept保证,指函数绝不会抛出任何异常,违反时程序调用std::terminate()终止;C++11起统一用noexcept说明符,其对move操作和容器优化至关重要。
在 C++ 中,nothrow 保证(更准确应称 noexcept guarantee)是异常安全的最高级别:函数承诺**绝不会抛出任何异常**。它不是“可能不抛”,而是编译器可验证、运行时强制的契约——若违反(比如 noexcept 函数内部抛了异常),程序会立即调用 std::terminate() 终止。
注意:nothrow 是旧式写法(C++98/03 中用于 new 表达式),C++11 起统一用 noexcept 说明符或说明符表达式。现在说 “nothrow 保证” 实际指 noexcept 语义下的强保证。
声明方式直接、显式,但容易误用:
void f() noexcept; —— 明确承诺不抛异常void g() noexcept(true); —— 等价于上一行void h() noexcept(false); —— 明确允许抛异常(默认行为)template void swap(T& a, T& b) noexcept(noexcept(a.swap(b))); —— 使用 noexcept 操作符做条件推导关键点:
立即学习“C++免费学习笔记(深入)”;
noexcept,即使函数体为空或只调用其他 noexcept 函数,也必须显式标注noexcept 是函数类型的一部分:void(*)() noexcept 和 void(*)() 是不同类型,不能互相赋值noexcept 的;若手动声明为 noexcept(false),且实际抛异常,仍会触发 std::terminate()
标准库容器(如 std::vector)在扩容、重排时是否启用移动而非拷贝,取决于元素类型的移动操作是否具备 noexcept 保证:
std::vector::push_back 在需要重新分配时,若 T 的移动构造函数是 noexcept,则优先移动;否则退回到拷贝(因为拷贝失败可回滚,移动若抛异常则无法保证强异常安全)std::vector::resize、std::sort 等算法也会依赖 noexcept 移动来启用优化路径noexcept,否则破坏容器行为struct Widget {
Widget(Widget&&) noexcept; // ✅ 若底层资源转移无异常风险(如 raw pointer 交换)
// Widget(Widget&&) { /* 可能抛
std::bad_alloc */ } // ❌ 不该标 noexcept
};看似安全的操作,实际可能隐式抛异常:
delete p; 本身不抛,但若 p 是 unique_ptr 且其自定义删除器抛异常,则整个移动/销毁可能破环 noexcept
std::vector::data() 是 noexcept,但 std::vector::at() 不是(下标越界抛 std::out_of_range)noexcept;仅看函数签名不够(比如未标注的函数默认 noexcept(false))noexcept 表达式时,若未覆盖所有实例化分支,可能在某些类型下意外变成 noexcept(false)
最易被忽略的是:异常安全级别不是静态属性,它依赖整个调用链的每一步——哪怕一个 noexcept 函数里调用了未标记的普通函数,整条路径就失去 noexcept 保证。