Noexcept 说明符
背景
在 C++11 之前,C++ 提供了 throw
规范用于声明一个函数可能抛出的异常类型,例如:
void func() throw(int, double); // 表示 func 可能抛出 int 或 double 类型的异常
但是,这种规范有以下几个主要问题:
- 运行时检查:
throw
规范在函数运行时进行异常类型的检查。如果函数抛出的异常类型不在规范范围内,程序会调用std::unexpected
,通常会导致程序崩溃。std::unexpected
是 C++98 中的机制,当一个函数抛出了未列入throw
规范的异常时,会调用该函数。- 默认情况下,
std::unexpected
会调用std::terminate
,从而终止程序。 - 开发者可以通过
std::set_unexpected
自定义处理逻辑,但这种机制的实际使用价值较低,尤其在性能敏感场景中。
- 性能开销:由于需要在运行时进行检查,这会引入额外的性能开销。
- 限制性不足:
throw
规范的可读性和实用性较低,开发者往往选择忽略这种用法。
此外,std::terminate
是 C++ 中的一个核心函数,用于在无法继续执行的异常场景下终止程序。
- 触发场景:
- 无捕获的异常。
- 栈展开时发生了新的异常(双重异常)。
- 手动调用
std::terminate
。
- 自定义行为:开发者可以通过
std::set_terminate
设置终止行为的自定义逻辑,但默认行为是直接退出程序。
由于上述问题,C++11 引入了更高效的 noexcept
关键字来替代 throw
规范。
noexcept 特性简介
noexcept
是一种用于声明函数不会抛出异常的关键字,它相比 throw
规范提供了以下改进:
- 编译期检查:
noexcept
能够在编译期确定函数是否可以抛出异常,从而避免运行时检查带来的开销。 - 性能优化:编译器可以利用
noexcept
的信息对代码进行优化,例如在std::move
和容器操作中。 - 语义清晰:
noexcept
明确声明了函数的异常安全性,增强了代码的可读性和可维护性。
noexcept
的语法如下:
void func() noexcept; // 表示 func 不会抛出异常
此外,还可以使用 noexcept(expression)
形式,其中 expression
是一个布尔表达式,返回值为 true
时表示函数不会抛出异常。
vo