结论:noexcept本身不提速,但它让编译器敢删掉异常栈展开逻辑、让标准库敢用移动代替拷贝——这才是性能提升的真正来源;std::vector扩容时若移动构造函数未标noexcept,将强制退化为拷贝,因标准要求仅当移动操作noexcept时才允许替代拷贝。
直接说结论:noexcept本身不提速,但它让编译器敢删掉异常栈展开逻辑、让标准库敢用移动代替拷贝——这才是性能提升的真正来源。
当std::vector需要重新分配内存,它会把旧元素搬到新内存。搬的方式取决于元素类型的移动构造函数是否标记为noexcept:
MyClass(MyClass&&) noexcept成立 → 搬用移动,O(1)资源转移noexcept或标了noexcept(false) → 退化为拷贝,O(n)深拷贝+原地析构这不是“建议”,是标准强制行为。哪怕你的移动构造函数实际从不抛异常,只要没写noexcept,std::vector就默认它危险,不敢动。
你不能硬写MyClass(MyClass&&) noexcept,因为内部可能调用成员的移动构造——而成员是否noexcept得看类型。正确写法是:
立即学习“C++免费学习笔记(深入)”;
MyClass(MyClass&& other) noexcept( noexcept(std::move(other.data_)) && noexcept(std::move(other.handle_))) { ... }
这里外层noexcept(...)是说明符,内层noexcept(...)是操作符,编译期求值布尔结果。常见错误:
noexcept判断,导致整个函数被判定为可能抛异常noexcept括号里写了运行时表达式(如noexcept(x > 0)),编译失败noexcept能检测实际行为——它只看函数声明,不看函数体标对了带来优化,标错了程序崩溃(std::terminate)。关键分界线很明确:
noexcept,显式写出更清晰)swap、hash特化、std::tuple相关操作——标准库很多地方要求noexcept
new、std::string::at()、dynamic_cast(引用)、文件IO、网络调用的函数——这些都可能抛异常一个典型陷阱:std::vector::push_back本身不是noexcept,但如果你把它塞进一个宣称noexcept的包装函数里,就等于埋雷。
标了noexcept后,编译器不会生成异常栈展开表(.eh_frame段)、不会插入try/catch保护帧、函数调用路径更短。实测影响:
真正容易被忽略的是:noexcept声明必须在声明和定义中完全一致,少一个noexcept都会导致链接时报错,而不是编译报错。