首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Effective Modern C++ 條款 14:noexcept——優化與介面契約的雙重價值

     編輯:關於C++

從 C++98 到 C++11:異常規範的簡化

C++98 throw() 異常規範複雜、脆弱、編譯器難以優化。C++11 推出 noexcept:非黑即白——函式要麼可能拋出異常,要麼保證不拋出(noexcept)。

noexcept 的兩大核心價值

1. 介面契約:呼叫端可查詢並依賴

函式是否 noexcept 影響呼叫端的異常安全與效率決策。知道不拋異常卻不標記 noexcept,屬於介面設計缺失。

2. 編譯器優化:生成更高效目標碼

RetType func(params) noexcept; // 最大優化:無需維護堆疊展開資訊、析構順序
RetType func(params) throw();  // C++98 風格:無優化彈性
RetType func(params);          // 可能拋出:無優化

noexcept 允許編譯器省略異常處理機制的設置/銷毀開銷。

移動語意與 noexcept 的關鍵互動

std::vector::push_back 擴容時需將舊元素遷移至新記憶體。C++98 採用複製(強異常安全);C++11 想用移動(更快),但移動若拋出異常會破壞強異常安全(已移動元素無法回滾)。

策略:移動若 noexcept 則用移動,否則退回複製("move if you can, but copy if you must")。標準庫容器(vector、deque 等)通過 noexcept 檢測移動建構/指派是否安全。

swap 与 noexcept 的連鎖效應

標準庫 swap 是否 noexcept 取決於元素 swap 是否 noexcept:

template 
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))); // 陣列 swap

template 
struct pair {
    void swap(pair& p) noexcept(noexcept(swap(first, p.first)) && noexcept(swap(second, p.second)));
};

高層資料結構 swap noexcept 要求低層組件 swap noexcept,這激勵我們為自訂類型提供 noexcept swap。

正確性優先:謹慎承諾

  • noexcept 是介面承諾,違反導致 std::terminate。僅在確信長期不拋出異常時標記。
  • 大多數函式為 exception-neutral(不主動拋出,但透傳下層異常),不適用 noexcept。
  • 移動建構/指派、swap、記憶體釋放函式、解構函式——天然適合 noexcept,收益顯著。

預設 noexcept 與合約區分

  • 解構函式、operator delete 預設隱式 noexcept(除非成員明確 noexcept(false))。
  • Wide contract(無前置條件)函式適合標記 noexcept;Narrow contract(有前置條件,違反即 UB)標記需謹慎——若內部檢查前置條件並拋出異常,將與 noexcept 衝突。

編譯器不強制檢查一致性

void setup(); // 文檔說不拋出,但未標記 noexcept
void cleanup();
void doWork() noexcept { setup(); ... cleanup(); } // 合法,編譯器不警告

合法場景存在(如 C 庫函式、未遷移的 C++98 代碼),故編譯器不強制驗證。

總結

  1. noexcept 是介面一部分,呼叫端可能依賴。
  2. noexcept 函式優化優於非 noexcept。
  3. 移動操作、swap、釋放函式、解構函式受益最大。
  4. 多數函式為 exception-neutral,非 noexcept。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved