noexcept 是编译期无开销的异常承诺,throw() 是运行期有开销且已废弃的动态规范;前者直接 terminate,后者调用 unexpected;noexcept 支持常量表达式和编译时探测,影响重载、优化及标准库实现。
noexcept 和 throw() 的核心区别在于:前者是编译期、无开销、语义明确的异常承诺;后者是运行期、有开销、已被淘汰的动态异常规范。
throw() 是 C++98 引入的动态异常规范,写在函数声明末尾,表示“该函数不抛出任何异常”。但它本质是运行时检查机制——若违反,先调用 std::unexpected(),再可能终止程序。
noexcept 是 C++11 引入的关键字,本身是编译期常量表达式。noexcept 或 noexcept(true) 表示“绝不抛出”,一旦抛出,直接调用 std::terminate(),跳过所有异常栈展开逻辑。
中的 expr 必须是编译期可判定的常量表达式,例如 noexcept(std::is_nothrow_move_constructible_vthrow() 声明无法被编译器可靠信任——它不参与重载决议,也不影响内联或调用约定选择,因为实际行为只能在运行时验证。
noexcept 提供强契约保证,编译器可据此激进优化:
C++11 后,标准库中几乎所有原本用 throw() 声明的函数(如 operator new、析构函数、swap 等)都已改用 noexcept。例如:
void* operator new(std::size_t) throw(std::bad_alloc);
void* operator new(std::size_t) noexcept(false);(显式允许抛出)用户自定义类型中,若希望 move 操作被容器高效利用,必须显式标注 noexcept,否则 std::vector 在 resize 时将避免移动而选择拷贝。
throw() 允许用户通过 set_unexpected 自定义 std::unexpected 处理器,带来调试灵活性但也引入不确定性;noexcept 彻底放弃这一层,抛出即 terminate——这是有意为之的设计取舍:用确定性换简洁性和性能。
这意味着 noexcept 更适合系统级、实时或资源敏感场景,而 throw() 的“可干预”特性反而成了维护负担和安全盲区。