使用 noexcept 我們需要知道什麼?
noexcept 是什麼?
noexcept 是自 C++11 引入的新特性,指定函數是否可能會引發異常,以下是 noexcept 的標準語法:
noexcept-expression:
noexcept
noexcept(** *constant-expression* **)
constant-expression 是一個 bool
類型的常量表達式,是一種異常規範(exception specification),屬於C++的語言特性,表示是否會發生異常。
noexcept
等效於 noexcept(true)
。
noexcept(true)
或者 noexcept
表示函數不會拋出或者傳遞異常,如果函數發生異常,將調用 std::terminate
立即終止程式。
noexcept(false)
or 或者不使用 noexcept
(析構函數或釋放函數默認聲明為 noexcept
), 表示函數所有可能的異常都會被拋出.
應該使用 nonexcept 的情形
建議將所有不會拋出異常(包括以後)的函數聲明為 noexcept
。
當函數聲明為 noexcept
後,編譯器能夠在一些不同的上下文環境中產生更加高效的程式碼。
不應該使用 nonexcept 的情形
函數可以標記為 noexcept
當且僅當內部調用的所有函數也都直接或者間接的標記為 noexcept
或者 const
。
編譯器沒有義務檢查所有層級程式碼是否會拋出異常到 noexcept
函數。
如果標記了 noexcept
的函數確實拋出了異常,那麼std::terminate
將會被立即調用,並且不能保證函數內部的對象能夠被析構。
比起優化,正確性更為重要。
當你在最開始聲明一個函數為 noexcept
, 而後又反悔想要去掉 noexcept
標記,那麼你將會影響到調用端的程式碼。
示例
下面的函數被標記為有條件的 noexcept
:函數是否為 noexcept
取決於 noexcept
的子句表達式是否為 noexcept
。
例如,有兩個包含 Widget 對象的數組,交換兩個數組的函數是否為 noexcept
取決於 交換兩個數組中元素的函數是否為 noexcept
,即,交換兩個 Widget 對象是否為 noexcept
。
因此 Widget 對象 swap 的實現決定了 Widget 數組的交換函數是否為 noexcept
。
同樣地,包含 Widgets 的 std::pair 對象的交換函數是否應該為 noexcept
取決於交換兩個 Widget 對象是否為 noexcept
。
上層的數據結構操作可以為 noexcept
僅當下層的數據結構操作為 noexcept
。這就促使你,只要允許,就儘可能地提供 noexcept
的函數。
template <class T, size_t N>
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));
template <class T1, class T2>
struct pair {
…
void swap(pair& p) noexcept(noexcept(swap(first, p.first)) && noexcept(swap(second, p.second)));
…
};
總結
noexcept
是函數介面的一部分,這意味著調用者會依賴它。noexcept
函數可優化性要高於non-noexcept
函數。noexcept
用在數據移動,交換,記憶體釋放函數,析構函數中會更有價值。- 大多數函數本質上是屬於
non-noexcept
的。
擴展
在 C++17 之前還有一種異常規範 (dynamic exception pecification) throw(optional_type_list)
。
C++17 之後 throw(optional_type_list)
已被移除(除了 throw()
),throw()
等同於 noexcept
。
應該避免使用 throw(optional_type_list)
或者 throw()
。