C++中的noexcept关键字有什么用?(向编译器保证函数不抛出异常)

noexcept是编译期契约,声明函数绝不抛异常;违反则直接调用std::terminate终止程序。最应添加的场景是移动构造/赋值、析构函数及确定无异常的工具函数。

noexcept 用来告诉编译器“这个函数绝不会抛出异常”

它不是运行时检查,而是编译期契约:一旦你标记了 noexcept,函数体内若出现未捕获的异常(比如调用了一个可能抛异常的函数又没处理),程序会直接调用 std::terminate() 终止,而不是栈展开。这能避免异常传播开销,也让编译器有机会做更激进的优化(比如移动操作、内联判断)。

哪些函数加 noexcept 最有价值?

主要是移动构造函数、移动赋值运算符、析构函数,以及你明确控制所有子调用且已确认无异常路径的工具函数。标准库容器在做内存重分配或元素移动时,会优先选择 noexcept 的移动操作——否则退回到更慢的拷贝。

  • 移动构造函数不加 noexceptstd::vector::resize() 可能拒绝移动而改用拷贝
  • 析构函数默认是 noexcept(true);显式写成 ~T() noexcept 更清晰
  • 普通成员函数加 noexcept 前,务必确认所有调用链(包括 newoperator[]、自定义函数)都不抛异常

noexcept 后面可以跟括号表达式,别乱用

noexcept 不只是个关键字,它是个运算符,支持 noexcept(expr) 形式,返回 bool 编译期常量。常见写法:

void f() noexcept(n

oexcept(g()) && noexcept(h())); // 只有 g 和 h 都不抛,f 才 noexcept

但注意:noexcept(g()) 检查的是 g 的声明,不是运行时行为;如果 g 声明为 noexcept,那整个表达式就是 true。滥用嵌套会让代码难读,多数场景直接写 noexcept 就够了。

加了 noexcept 却意外抛异常,后果很直接

不是报错或警告,而是运行时崩溃——调用 std::terminate(),没有栈展开,资源不自动释放。调试时容易误判为段错误。常见踩坑点:

  • noexcept 函数里调用了没加 noexcept 的第三方函数(比如某些 STL 算法未标注)
  • 写了 throw;throw std::runtime_error(...); —— 这是硬编码违规
  • 使用 new 时没配 std::nothrow,而系统内存不足触发 std::bad_alloc
  • 访问 std::vector::operator[] 越界不抛异常,但 at() 会抛 —— 别在 noexcept 函数里用 at()

真正关键的不是“能不能加”,而是“敢不敢保证”。一旦加了,就得对整条调用链负全责。