noexcept
noexcept 说明符
指定函数是否抛出异常。
语法 |
说明 |
noexcept |
与 noexcept(true) 相同 |
noexcept(表达式) |
如果 表达式 求值为 true,那么声明函数不会抛出任何异常。后随 noexcept 的 ( 只能是该形式的一部分(它不是初始化器的开始)。 |
noexcept 说明不是函数类型的一部分(正如同动态异常说明),而且只能在声明函数、变量、函数类型的非静态数据成员、函数指针、函数引用或成员函数指针时,以及在以上这些声明中声明类型为函数指针或函数引用的形参或返回类型时,作为 lambda 声明符或顶层函数声明符的一部分出现。它不能在 typedef 或类型别名声明中出现。
C++ 中的每个函数要么不会抛出,要么有可能会抛出。
有可能会抛出的函数是:
- 声明带有求值为 false 的 表达式 的 noexcept 说明符的函数
- 声明不带有 noexcept 声明的函数,除了
- 析构函数,除非有任何可能在构造的基类或成员的析构函数有可能会抛出
- 隐式声明的或在它的首个声明被预置的默认构造函数、复制构造函数、移动构造函数,除非
- 由构造函数的隐式定义所调用的某个基类或成员的构造函数有可能会抛出
- 这种初始化的某个子表达式,例如默认实参表达式,有可能会抛出
- (默认构造函数的)默认成员初始化器有可能会抛出
- 隐式声明的或在它的首个声明被预置的复制赋值运算符、移动赋值运算符,除非隐式定义中对任何赋值运算符的调用有可能会抛出
- 解分配函数
- 所有其他函数(以求值为 true 的 表达式 的 noexcept 说明符声明的函数,以及析构函数、预置的特殊成员函数和解分配函数)都不会抛出
1 2 3 4
| void f() noexcept; void f(); void g() noexcept(false); void g();
|
如果虚函数不会抛出,那么它每个覆盖的函数的所有声明(包括定义)都必须不抛出,除非覆盖函数被定义为弃置:
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct B { virtual void f() noexcept; virtual void g(); virtual void h() noexcept = delete; }; struct D : B { void f(); void g() noexcept; void h() = delete; };
|
noexcept 运算符
noexcept 运算符进行编译时检查,如果表达式不会抛出任何异常则返回 true。
它可用于函数模板的 noexcept 说明符中,以声明函数将对某些类型抛出异常,但不对其他类型抛出。
语法
noexcept( 表达式 )
返回 bool 类型的纯右值。
解释
noexcept 运算符不会对 表达式 求值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include <iostream> #include <utility> #include <vector> void may_throw(); void no_throw() noexcept; auto lmay_throw = []{}; auto lno_throw = []() noexcept {}; class T { public: ~T(){} }; class U { public: ~U(){} std::vector<int> v; }; class V { public: std::vector<int> v; }; int main() { T t; U u; V v; std::cout << std::boolalpha << "may_throw() 可能会抛出异常吗?" << !noexcept(may_throw()) << '\n' << "no_throw() 可能会抛出异常吗?" << !noexcept(no_throw()) << '\n' << "lmay_throw() 可能会抛出异常吗?" << !noexcept(lmay_throw()) << '\n' << "lno_throw() 可能会抛出异常吗?" << !noexcept(lno_throw()) << '\n' << "~T() 可能会抛出异常吗?" << !noexcept(std::declval<T>().~T()) << '\n' << "T(T 右值) 可能会抛出异常吗?" << !noexcept(T(std::declval<T>())) << '\n' << "T(T 左值) 可能会抛出异常吗?" << !noexcept(T(t)) << '\n' << "U(U 右值) 可能会抛出异常吗?" << !noexcept(U(std::declval<U>())) << '\n' << "U(U 左值) 可能会抛出异常吗?" << !noexcept(U(u)) << '\n' << "V(V 右值) 可能会抛出异常吗?" << !noexcept(V(std::declval<V>())) << '\n' << "V(V 左值) 可能会抛出异常吗?" << !noexcept(V(v)) << '\n'; }
输出:
may_throw() 可能会抛出异常吗?true no_throw() 可能会抛出异常吗?false lmay_throw() 可能会抛出异常吗?true lno_throw() 可能会抛出异常吗?false ~T() 可能会抛出异常吗?false T(T 右值) 可能会抛出异常吗?false T(T 左值) 可能会抛出异常吗?false U(U 右值) 可能会抛出异常吗?true U(U 左值) 可能会抛出异常吗?true V(V 右值) 可能会抛出异常吗?false V(V 左值) 可能会抛出异常吗?true
|
noexcept 修饰符有两种形式:
- 一种就是简单地在函数声明后加上 noexcept 关键字,表示其修饰的函数不会抛出异常。 比如:
void excpt_func() noexcept;
- 另外一种则可以接受一个常量表达式作为参数:
void excpt_func() noexcept ( 常量表达式 );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| #include <iostream> using namespace std;
void Throw() { throw 1; }
void NoBlockThrow() { Throw(); }
void BlockThrow() noexcept { Throw(); }
template<typename T> void func(T) noexcept(noexcept(T())) {}
struct A { ~A() { throw 1; } };
struct B { ~B() noexcept(false) { throw 2; } };
struct C { B b; };
void funcA() { A a; } void funcB() { B b; } void funcC() { C c; }
#define run2
int main() { #ifdef run1 try { Throw(); } catch (...) { cout << "Found throw." << endl; }
try { NoBlockThrow(); } catch (...) { cout << "Throw is not blocked." << endl; }
func(1); try { BlockThrow(); } catch(...) { cout << "Found throw 1." << endl; }
#elif defined(run2)
try { funcB(); } catch(...) { cout << "caught funcB." << endl; }
try { funcC(); } catch(...) { cout << "caught funcC." << endl; }
try { funcA(); } catch(...) { cout << "caught funcA." << endl; }
#endif
return 0; }
|