一. 概述
noexcept 是C++11中的特性,既是一個說明符,也是一個運算符。能夠說明函數是否會拋出異常,如下:
1 struct X { 2 3 int f() const noexcept { 4 return 58; 5 } 6 7 void g() noexcept {} 8 }; 9 10 int foo() noexcept { 11 return 42; 12 }
noexcept指示上述的幾個函數不會拋出異常,編譯器可以優化代碼。
如果有異常拋出,則會調用std::terminate結束生命周期。
二. 帶參數的noexcept
帶參數的noexcept作用為:如果noexcept(true),則不會拋出異常,反之則可能有異常,下面的例子中,可以用noexcept檢查傳入模板參數是不是基礎類型。
1 template <class T> 2 T copy(const T& o) noexcept(std::is_fundamental<T>::value) { 3 ... 4 }
這個函數可以優化為:
1 template <class T> 2 T copy(const T& o) noexcept(noexcept (T(o))) { 3 4 }
這里用了2個noexcept,第二個判斷T(o)是否可能拋出異常,第一個接受第二個的返回值,決定T類型復制函數是否聲明為不拋出異常
三. noexcept使用場景
1. 解決移動構造和移動賦值的問題
下例用noexcept實現一個移動語義的容器經常用到的工具函數swap。如果move沒有拋出異常的可能,那么函數進行移動操作,否則進行復制操作。
1 template <class T> 2 void swap(T &a, T &b) 3 noexcept(noexcept (T(std::move(a))) && noexcept (a.operator=(std::move(b)))) { 4 static_assert (noexcept (T(std::move(a))) && noexcept (a.operator=(std::move(b))) ); 5 T temp(std::move(a)); 6 a = std::move(b); 7 b = std::move(temp); 8 }
2. 用於析構函數。在新版本的編譯器中,析構函數是默認加上關鍵字noexcept的。
3. 葉子函數。葉子函數是指在函數內部不分配棧空間,也不調用其它函數,也不存儲非易失性寄存器,也不處理異常。
四. 注意事項
1. 在新版本編譯器中,默認構造函數,默認復制構造函數,默認賦值函數,默認移動構造函數,默認移動賦值函數均自帶noexcept,但使用者自定義或重載的上述函數需要手動加上noexcept才有此功能。
2. c++11中保留了throw(), 實現和noexcept類似的功能,區別是throw()不會針對編譯器進行優化,但是C++20中移除了throw()。
