例外
例外處理提供了一種將控制權與資訊從程式執行過程中的某一點,轉移至先前執行路徑上相關聯之處理器的方法(換句話說,例外處理會沿著呼叫堆疊向上傳遞控制權)。
求值一個 throw 表達式將會拋出一個例外。例外也可以在其他環境中拋出。
為了捕捉例外,throw 表達式必須位於 try 區塊內,且該 try 區塊必須包含一個與該例外物件類型相符的處理器。
宣告函式時,可以提供下列規格來限制函式可能拋出的例外類型:
| (直到 C++17) |
| (C++11 起) |
例外處理期間產生的錯誤由 std::terminate 與 std::unexpected(C++17 前) 處理。
目錄 |
[編輯] 用法
雖然 throw 表達式可用於將控制權轉移至執行堆疊上任意區塊的程式碼(類似 std::longjmp),但其預期的用途是錯誤處理。
[編輯] 錯誤處理
拋出例外用於標示函式發生的錯誤,此處的「錯誤」通常僅限於下列情況[1][2][3]
- 未能滿足後置條件,例如無法產生有效的回傳值物件。
- 未能滿足必須呼叫的另一個函式之前置條件。
- (針對非私有成員函式)未能(重新)建立類別的不變量(class invariant)。
特別地,這意味著建構子(另見 RAII)與大多數運算子的失敗應該透過拋出例外來報告。
此外,所謂的「寬合約」(wide contract)函式會使用例外來指出不可接受的輸入。例如,std::basic_string::at 沒有前置條件,但會透過拋出例外來指出索引超出範圍。
[編輯] 例外安全性
當函式報告錯誤狀況後,程式的狀態可能會提供額外的保證。通常公認有以下四種例外保證等級[4][5][6],它們彼此之間是嚴格的超集關係:
- 無拋出(或無失敗)例外保證 (Nothrow/Nofail guarantee) — 函式永遠不會拋出例外。解構子及其他在堆疊展開期間可能被呼叫的函式,預期應具備無拋出特性(錯誤透過其他方式報告或隱藏)。解構子預設為
noexcept。(C++11 起) 無失敗(函式總是成功)預期應用於 swap、移動建構子,以及其他被提供強例外保證之函式所使用的函式。 - 強例外保證 (Strong exception guarantee) — 若函式拋出例外,程式狀態會回滾至函式呼叫前的狀態(例如 std::vector::push_back)。
- 基本例外保證 (Basic exception guarantee) — 若函式拋出例外,程式處於有效狀態。不會發生資源洩漏,且所有物件的不變量皆維持完整。
- 無例外保證 (No exception guarantee) — 若函式拋出例外,程式可能處於無效狀態:可能已發生資源洩漏、記憶體損毀,或其他破壞不變量的錯誤。
通用元件(Generic components)可能還提供例外中立保證 (exception-neutral guarantee):若例外從範本參數拋出(例如從 std::sort 的 Compare 函式物件,或 std::make_shared 中 T 的建構子拋出),該例外將原封不動地傳播給呼叫者。
[編輯] 例外物件
雖然任何完整類型的物件及指向 void 的 cv 限定指標皆可作為例外物件拋出,但所有標準程式庫函式皆透過值拋出未命名的物件,且這些物件的類型(直接或間接)衍生自 std::exception。使用者定義的例外通常也遵循此模式。[7][8][9]
為了避免不必要的例外物件複製以及物件切割(object slicing),處理器的最佳做法是以參考方式捕捉。[10][11][12][13]
[編輯] 附註
| 特性測試巨集 | 數值 | 標準 | 功能 |
|---|---|---|---|
__cpp_constexpr_exceptions |
202411L |
(C++26) | constexpr 例外 |
[編輯] 外部連結
|