noexcept修飾符,noexcept操作符
noexcept的兩個作用:
1)作為noexcept修飾符,宣告函式是否丟擲異常;
2)作為noexcept操作符,判斷表示式是否丟擲異常;
noexcept修飾符
noexcept修飾符有兩種形式:一種是簡單在函式聲明後加noexcept,另一種是接受一個常量表達式作為引數,如:
void except_func() noexcept; // 這裡noexcept作為修飾符
void except_func() noexcept(常量表達式); // 這裡noexcept作為運算子
宣告為noexcept的函式丟擲了異常,會怎麼樣?
如果一個函式宣告為noexcept,但還是丟擲了異常,會直接呼叫std::terminate中斷程式的執行。
注:C++98中,用throw()來宣告不丟擲異常,throw(異常型別)宣告可能丟擲的異常型別。noexcept效率比throw更高一些,因為編譯器可以用std::terminate()來終止程式執行,而throw異常機制會有一些額外開銷,如函式棧依次展開並析構自動變數。
例1,C++98中,用throw()宣告不丟擲異常的函式:
template<class T> class A{ public: static constexpr T min() throw() { return T(); } static constexpr T max() throw() { return T(); } static constexpr T lowest() throw() { return T(); } ... };
相應地,在C++11中,使用noexcept替換throw()
template<class T> class A{
public:
static constexpr T min() noexcept { return T(); }
static constexpr T max() noexcept { return T(); }
static constexpr T lowest() noexcept { return T(); }
...
};
noexcept操作符
noexcept普通形式
noexcept(e);
可以讓一個函式f()是否丟擲異常,與另一個函式g()保持一致:
void f() noexcept(noexcept(g())); // f和g的異常說明保持一致
改寫成讓f()是否丟擲異常,取決於模板引數T()表示式:
template<class T>
void f() noexcept(noexcept(T())) { }
例2,C++98中,用throw()宣告可能丟擲std::bad_alloc異常的函式:
void* operator new(std::size_t) throw(std::bad_alloc);
void* operator new[](std::size_t) throw(std::bad_alloc);
相應地,C++11中,可用noexcept(false)來替代throw
void* operator new(std::size_t) noexcept(false);
void* operator new[](std::size_t) noexcept(false);
可以看到,noexcept宣告函式可能丟擲的異常時,無需指明具體的型別,而throw卻需要指明。
不過,出於安全考慮,C++11標準中,類的解構函式預設是noexcept(true)。如果顯示指定noexcept或noexcept(false),就不會再保持預設值。
參考
[1]MichaelWon, IBM XL編譯器中國開發團隊. 深入理解C++11:C++11新特性解析與應用[M]. 機械工業出版社, 2013.