C++11 noexcept修饰符与noexcept操作符

noexcept修饰符与noexcept操作符

首先,明确一点:

在C++11之后,表示函数不会抛出异常的动态异常声明throw()被新的noexcept异常声明所取代。

在通常情况下,在C++11中使用noexcept可以有效的阻止异常的传播与扩散。

【1】noexcept修饰符

从语法上讲,noexcept修饰符有两种形式:

(1)在函数声明后直接加上关键字noexcept

noexcept形如其名,表示其修饰的函数不会抛出异常。不过与throw()动态异常声明不同的是:

在C++11中如果noexcept修饰的函数结果却抛出了异常,编译器可以选择直接调用std::terminate()函数来终止程序的运行,这比基于异常机制的throw()在效率上会高一些。

这是因为异常机制会带来一些额外开销,比如函数抛出异常,会导致函数栈被依次地展开(unwind),并依帧调用在本帧中已构造的自动变量的析构函数等。

(2)在(1)的关键字后再加一个参数(常量表达式)

若常量表达式转换成bool类型的值为true,说明不会抛出异常;反之,则可能会抛出异常。

其实,回头再看第一种形式,不带常量表达式的noexcept相当于声明了noexcept(true),即不会抛出异常。

以上示例如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void my_exception()
 5 {
 6     throw 1;
 7 }
 8 
 9 void my_exception_noexcept_false() noexcept(false)
10 {
11     throw 1;
12 }
13 
14 void my_exception_noexcept_true() noexcept
15 {
16     throw 1;
17 }
18 
19 int main()
20 {
21     try
22     {
23         my_exception();
24     }
25     catch (...)
26     {
27         cout << "throw my_exception" << endl;  // throw my_exception
28     }
29 
30     try
31     {
32         my_exception_noexcept_false();
33     }
34     catch (...)
35     {
36         cout << "throw noexcept_false" << endl; // throw noexcept_false
37     }
38 
39     try
40     {
41         // warning C4297 : “my_exception_noexcept_true”: 假定函数不引发异常,但确实发生了
42         my_exception_noexcept_true();          // terminate
43     }
44     catch (...)
45     {
46         cout << "throw noexcept_true " << endl;   
47     }
48 }

注意:本地VS2019环境,在编译my_exception_noexcept_true时,报出警告warning C4297:假定函数不引发异常,但确实发生了

【2】noexcept操作符

(1)noexcept作为操作符noexcept(expression),noexcept操作符不对expression求值。

若expression含有至少一个下列潜在求值的构造则结果为false:

[1] 调用没有指定不抛出异常的任意类型函数,除非它是常量表达式。

[2] throw表达式。

[3] 目标类型是引用类型,且转换时需要运行时检查的dynamic_cast表达式。

[4] 参数类型是多态类类型的typeid表达式。

示例如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void test() { }
 5 void test_noexcept() noexcept(true) { }
 6 void test_noexcept_false() noexcept(false) { }
 7 
 8 class Base
 9 {
10 public:
11     virtual void f() {}
12 };
13 
14 class Test : public Base
15 {};
16 
17 int main(int argc, char** argv)
18 {
19     cout << noexcept(test()) << endl;                       // false
20     cout << noexcept(test_noexcept()) << endl;              // true
21     cout << noexcept(test_noexcept_false()) << endl;        // false
22     cout << noexcept(throw) << endl;                        // false
23 
24     Test test;
25     Base& base = test;
26     cout << noexcept(dynamic_cast<Test&>(base)) << endl;     // false
27     cout << noexcept(typeid(base)) << endl;                  // false
28 }

(2)noexcept操作符用于模板。示例如下:

1 template <class T> 
2 void fun() noexcept(noexcept(T())) {}

这里,fun函数是否是一个noexcept的函数,将由T()表达式是否会抛出异常所决定。

这里的第二个noexcept就是一个noexcept操作符。

当其参数是一个有可能抛出异常的表达式的时候,其返回值为false,反之为true

应用示例如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template <typename T>
 5 void fun() noexcept(noexcept(T())) { throw 1; }
 6 
 7 class Base 
 8 {
 9 public:
10     virtual void f() { }
11 };
12 
13 class Test : public Base 
14 {
15 public:
16     ~Test() noexcept(true) { }
17 };
18 
19 class TestFalse : public Base
20 {
21 public:
22     ~TestFalse() noexcept(false) { }
23 };
24 
25 int main(int argc, char** argv)
26 {
27     cout << noexcept(TestFalse()) << endl; // false
28     cout << noexcept(Test()) << endl;      // true
29 
30     try
31     {
32         fun<TestFalse>();
33     }
34     catch (...)
35     {
36         cout << "throw" << endl;  // throw
37     }
38 
39     try
40     {
41         fun<Test>();    // terminate
42     }
43     catch (...)
44     {
45         cout << "throw" << endl;
46     }
47 
48     getchar();
49     return 0;
50 }

good good study, day day up.

顺序 选择 循环 总结

posted @ 2020-01-21 22:32  kaizenly  阅读(1227)  评论(0编辑  收藏  举报
打赏