noexcept关键字用于声明函数不抛异常,提升性能与安全性,替代旧式throw()规范,编译期确定无运行时开销,标准库优先使用noexcept移动构造函数优化容器操作,还可作为操作符在模板中条件化异常规范。
在c++中,noexcept关键字是异常规范(exception specification)的现代替代方案,用于表明一个函数是否会抛出异常。它不仅提升了代码的性能和安全性,还帮助编译器进行优化。
noexcept 的基本用法
使用 noexcept 可以明确指定函数不会抛出异常:
void myFunction() noexcept { }
上面的函数承诺不抛出异常。如果该函数内部或调用的函数抛出了异常,程序将直接调用 std::terminate() 终止运行,而不是进行栈展开。
也可以带条件:
立即学习“C++免费学习笔记(深入)”;
void mayThrow() noexcept(false);
表示这个函数可能抛出异常。虽然 noexcept(true) 等价于 noexcept,但条件形式可用于模板中根据类型特性决定是否异常安全。
与旧式异常规范的对比
C++98/03 中使用 throw() 作为异常规范:
void oldStyle() throw(); // 表示不抛异常(已废弃)
这种写法在运行时检查异常规范,违反时调用 std::unexpected(),性能开销大且难以控制。C++11 起推荐使用 noexcept,它在编译期尽可能确定,且不带来运行时开销。
更重要的是,noexcept 是编译器优化的重要提示。例如,标准库在移动构造函数中优先使用 noexcept 版本以提高容器重排效率。
在移动操作和标准库中的重要性
标准库容器(如 std::vector)在重新分配内存时,会优先使用 noexcept 的移动构造函数,以避免异常安全问题并提升性能。
例如:
class MyClass {
public:
MyClass(MyClass&& other) noexcept { /* 安全的移动 */ }
};
如果移动构造函数未标记为 noexcept,std::vector 可能改用复制而非移动,导致性能下降。
noexcept 作为操作符使用
noexcept 也可以作为操作符,在编译期判断表达式是否会抛异常:
template<typename T>
void fun(T& t) noexcept(noexcept(t.method())) { }
外层 noexcept 是规范,内层是操作符,返回一个布尔值。这在泛型编程中非常有用,可让函数的异常规范依赖于模板参数的行为。
基本上就这些。合理使用 noexcept 能提升程序效率和稳定性,特别是在移动语义和标准库交互中。它已完全取代旧式 throw() 规范,是现代C++的重要组成部分。