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.

順序 選擇 循環 總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM