关注公众号获取更多信息:
好久没有没有更新文章了,因为最近忙于A,B,C.....好吧我摊牌了。就是因为懒。这个文章是这个系列的倒数第三篇文章。C++11系列更新完了之后,我会更新其他编程相关的文章。
言归正传,今天讲的是noexcept。这个关键字也是属于你不知道它也能编出好程序的,没有存在感的一个关键字,但是用好它会让你的程序更加清晰,它会告诉编译器,这个函数不可能抛出异常,这样编译器对你的程序做更多的优化。由于C++中的异常处理是在运行时而不是编译时检测的。为了实现运行时检测,编译器创建额外的代码,然而这会妨碍程序优化。
说到noexcept包括两部分,一部分就是noexcept说明符,一个是noexcept运算符。我们分别说说
noexcept 说明符
意义:指定函数是否抛出异常。
语法:
noexcept | (1) | |
noexcept(表达式) | (2) | |
throw() | (3) | (弃用)(C++20 中移除) |
1) 与 noexcept ( true ) 相同
2) 若 表达式 求值为 true,则声明函数为不抛出任何异常。
3) 不抛出动态异常说明(不同于 noexcept(true),它保证进行栈回溯并可能调用 std::unexpected) | (C++17 前) |
3) 与 noexcept(true) 相同 | (C++17 起) (C++20 前) |
表达式 | - | 按语境转换为 bool 类型的常量表达式 |
需要注意的是:C++17前,noexcept 说明不是函数类型的一部分(正如同动态异常说明),而且只能在声明函数、变量、函数类型的非静态数据成员、函数指针、函数引用或成员函数指针时,以及在以上这些声明中声明类型为函数指针或函数引用的形参或返回类型时,作为 lambda 声明符或顶层函数声明符的一部分出现。它不能出现于 typedef 或类型别名声明中。
void f() noexcept; // 函数 f() 不抛出
void (*fp)() noexcept(false); // fp 指向可能抛出的函数
void g(void pfa() noexcept); // g 接收指向不抛出的函数的指针
// typedef int (*pf)() noexcept; // 错误
C++17后,noexcept 说明是函数类型的一部分,可以作为任何函数声明符的一部分出现。
noexcept 运算符
noexcept
运算符进行编译时检查,若表达式声明为不抛出任何异常则返回 true。这个具体看一个小例子就可以了,这里就不再展开了。
它可用于函数模板的 noexcept
说明符中,以声明函数将对某些类型抛出异常,但不对其他类型抛出。
如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。
语法
noexcept( 表达式 ) |
返回 bool 类型的纯右值。
解释
noexcept
运算符不对 表达式 求值。
若 表达式 的潜在异常集合为空 (C++17 前)表达式 为不抛出 (C++17 起) 则结果为 true,否则结果为 false。
例子
#include <iostream>
#include <utility>
#include <vector>
void may_throw();
void no_throw() noexcept;
auto lmay_throw = []{};
auto lno_throw = []() noexcept {};
class T{
public:
~T(){} // 析构函数妨碍了移动构造函数
// 复制构造函数为 noexcept
};
class U{
public:
~U(){} // 析构函数妨碍了移动构造函数
// 复制构造函数为 noexcept(false)
std::vector<int> v;
};
class V{
public:
std::vector<int> v;
};
int main()
{
T t;
U u;
V v;
std::cout << std::boolalpha
<< "Is may_throw() noexcept? " << noexcept(may_throw()) << '\n'
<< "Is no_throw() noexcept? " << noexcept(no_throw()) << '\n'
<< "Is lmay_throw() noexcept? " << noexcept(lmay_throw()) << '\n'
<< "Is lno_throw() noexcept? " << noexcept(lno_throw()) << '\n'
<< "Is ~T() noexcept? " << noexcept(std::declval<T>().~T()) << '\n'
// 注:以下各项测试也要求 ~T() 为 noexcept
// 因为 noexccept 中的表达式构造并销毁了临时量
<< "Is T(rvalue T) noexcept? " << noexcept(T(std::declval<T>())) << '\n'
<< "Is T(lvalue T) noexcept? " << noexcept(T(t)) << '\n'
<< "Is U(rvalue U) noexcept? " << noexcept(U(std::declval<U>())) << '\n'
<< "Is U(lvalue U) noexcept? " << noexcept(U(u)) << '\n'
<< "Is V(rvalue V) noexcept? " << noexcept(V(std::declval<V>())) << '\n'
<< "Is V(lvalue V) noexcept? " << noexcept(V(v)) << '\n';
}
输出:
Is may_throw() noexcept? false
Is no_throw() noexcept? true
Is lmay_throw() noexcept? false
Is lno_throw() noexcept? true
Is ~T() noexcept? true
Is T(rvalue T) noexcept? true
Is T(lvalue T) noexcept? true
Is U(rvalue U) noexcept? false
Is U(lvalue U) noexcept? false
Is V(rvalue V) noexcept? true
Is V(lvalue V) noexcept? false