noexcept 是 C++11 中引入的一个关键字,用来标记函数声明,表示该函数不会抛出异常。它可以用于函数、函数指针、Lambda 表达式等。使用 noexcept 可以帮助编译器进行优化,提高代码的执行效率,并且让程序在处理异常时更加明确。
1. 基本语法
void foo() noexcept {// 这个函数不会抛出异常
}void bar() {// 这个函数可能会抛出异常
}
2. 作用
- 提高性能:编译器知道一个函数不会抛出异常后,可以进行更多的优化(例如:不需要为异常处理创建额外的代码路径)。
- 异常安全性:显式地声明一个函数不会抛出异常,可以使代码的异常行为更清晰,增强代码的可维护性。
- 条件约束:可以用 noexcept 来限制函数的使用。例如,标准库中的 std::vector::swap 如果是 noexcept,那么它可以在 std::vector 中进行更多的优化。
3. 如何使用
标记函数:
使用 noexcept 修饰符来指示函数不抛出异常:
void foo() noexcept {// 函数实现
}
推断函数是否 noexcept:
C++11 中还引入了 noexcept 运算符,用来推断某个函数是否会抛出异常。
template<typename T>
void func(T&& arg) noexcept(noexcept(T(std::forward<T>(arg)))) {// 根据类型 T 的构造函数是否 noexcept 来决定是否 noexcept
}
4. noexcept 运算符
C++11 引入了 noexcept 运算符,可以用来检查某个表达式或类型是否会抛出异常:
template <typename T>
void check_if_noexcept() {if constexpr (noexcept(T())) {std::cout << "T() is noexcept\n";} else {std::cout << "T() is not noexcept\n";}
}
5. noexcept 与异常的关系
- 如果你声明一个函数为 noexcept,但该函数抛出了异常,程序将调用 std::terminate(),从而导致程序终止。这是因为 noexcept 函数承诺不会抛出异常,违背这一承诺会导致程序的未定义行为。
- 函数的 noexcept 状态可以通过以下规则推断:
- 如果函数体内包含任何可能抛出异常的操作,则该函数不应标记为 noexcept。
- 如果函数内部明确声明不抛出异常,例如函数内部只调用其他 noexcept 函数,则该函数可以标记为 noexcept。
6. 示例代码
#include <iostream>void foo() noexcept {std::cout << "foo is noexcept\n";
}void bar() {throw std::runtime_error("bar throws exception");
}int main() {foo(); // No exception, works finetry {bar(); // Throws exception, catch it} catch (const std::exception& e) {std::cout << e.what() << std::endl;}return 0;
}
7. noexcept 和 Lambda 表达式
C++11 允许你在 Lambda 表达式中使用 noexcept:
auto lambda = []() noexcept { std::cout << "This is noexcept lambda\n"; };
lambda();
8. 注意事项
- 默认情况下,函数不抛出异常:在 C++11 之前,函数没有明确标记为 noexcept,默认认为它可能会抛出异常。
- 函数指针与 noexcept:如果一个函数指针指向的函数被标记为 noexcept,你也需要明确声明函数指针为 noexcept:
void (*fp)() noexcept = foo;
总结
- noexcept 是 C++11 提供的一个关键字,标记函数不会抛出异常。
- 它可以帮助编译器进行性能优化,并增强代码的可维护性。
- 使用时需要注意不要在可能抛出异常的函数中标记为 noexcept,否则会导致程序终止。