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.
順序 選擇 循環 總結