noexcept 是向编译器承诺函数绝不会栈展开,违者调用 std::terminate;它决定标准容器是否选用移动而非拷贝操作,需显式声明并确保所有调用均满足该承诺。

noexcept 不是用来“声明函数不抛异常”的装饰,而是向编译器发出一个可验证的承诺:该函数在任何情况下都不会退出(即不会 stack-unwind)。一旦违反,程序直接调用 std::terminate —— 不是抛新异常,不是捕获,是立即终止。
noexcept 会影响 move 构造/赋值是否被自动选用
这是最常踩坑的点。标准容器(如 std::vector)在扩容时,若元素类型有 noexcept 移动构造函数,就优先用移动;否则退回到拷贝——哪怕你写了移动函数,只要没加 noexcept,编译器就认为“不安全”,不敢用。
-
std::vector的resize、push_back、reserve等操作依赖此判断 - 自定义类的移动构造函数必须显式写
T(T&&) noexcept,不能只靠= default(因为默认生成的版本是否noexcept取决于其成员是否都noexcept) - 检查方式:
static_assert(std::is_nothrow_move_constructible_v<mytype>);</mytype>
noexcept(expr) 是运行时检测,不是编译时断言
noexcept 后面跟括号时(如 noexcept(sizeof(T) > 4) 或 noexcept(std::is_nothrow_move_constructible_v<t>)</t>),它是个运算符,结果是 bool 常量表达式,用于模板推导或 SFINAE 场景。
-
noexcept(func())会尝试分析func的异常说明,但不执行func();若func未声明异常规格,则为false - 不要误以为
noexcept(ptr->foo())能捕获运行时异常——它只是查声明,不是 try/catch - 常见误用:
noexcept(my_vector.push_back(x))返回false,因为std::vector::push_back本身不是noexcept
noexcept(true) 和 noexcept(false) 的等价写法与陷阱
void f() noexcept 等价于 void f() noexcept(true);void f() noexcept(false) 显式表示可能抛异常(C++11 中曾用 throw(),已弃用)。
- 空
noexcept比noexcept(true)更常用,但二者语义完全一致 -
noexcept(false)几乎不用——除非你要在模板中特化控制异常传播行为,且明确需要覆盖默认推导 - 注意:析构函数默认是
noexcept(true),手动写~T() noexcept(false)是危险操作,可能导致栈展开中途崩溃
真正关键的不是“要不要加 noexcept”,而是“加了之后,所有被调用的函数是否真的满足这个承诺”。一个 noexcept 移动构造函数里调了可能抛异常的 new 或 std::string 操作,就是未定义行为触发点。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










