異常
異常處理提供了一種將控制和資訊從程式執行中的某個點傳輸到與先前執行點相關聯的處理程式(換句話說,異常處理將控制權沿呼叫棧向上傳輸)的方法。
評估 throw 表示式 將丟擲異常。異常也可以在其他上下文中丟擲。
為了捕獲異常,throw 表示式必須在 try 塊內,並且 try 塊必須包含與異常物件型別匹配的處理程式。
宣告函式時,可以提供以下規範以限制函式可能丟擲的異常型別
(C++17 前) |
(C++11 起) |
異常處理期間發生的錯誤由 std::terminate 和 std::unexpected(C++17 前) 處理。
目錄 |
[編輯] 用法
雖然 throw 表示式可用於出於任意原因將控制權傳輸到執行棧上方的任意程式碼塊(類似於 std::longjmp),但其預期用途是錯誤處理。
[編輯] 錯誤處理
丟擲異常用於從函式中發出錯誤訊號,其中“錯誤”通常僅限於以下幾點[1][2][3]
- 未能滿足後置條件,例如未能生成有效的返回值物件。
- 未能滿足必須呼叫的另一個函式的前置條件。
- (對於非私有成員函式)未能(重新)建立類不變式。
特別地,這意味著建構函式(參見 RAII)和大多數運算子的失敗應透過丟擲異常來報告。
此外,所謂的“寬契約”函式使用異常來指示不可接受的輸入,例如,std::basic_string::at 沒有前置條件,但丟擲異常來指示索引超出範圍。
[編輯] 異常安全
函式報告錯誤條件後,可能會提供關於程式狀態的額外保證。通常認可以下四級異常保證[4][5][6],它們是彼此的嚴格超集
- 不丟擲(或不失敗)異常保證 — 函式從不丟擲異常。不丟擲(錯誤透過其他方式報告或隱藏)是解構函式和其他在棧展開期間可能呼叫的函式的期望。解構函式預設是
noexcept
的。(C++11 起) 不失敗(函式總是成功)是交換操作、移動建構函式以及提供強異常保證的函式所使用的其他函式的期望。 - 強異常保證 — 如果函式丟擲異常,程式的狀態將回滾到函式呼叫之前的狀態(例如,std::vector::push_back)。
- 基本異常保證 — 如果函式丟擲異常,程式處於有效狀態。沒有資源洩漏,並且所有物件的不變式都完整無損。
- 無異常保證 — 如果函式丟擲異常,程式可能處於無效狀態:可能發生資源洩漏、記憶體損壞或其他破壞不變式的錯誤。
通用元件還可以提供異常中立保證:如果從模板引數(例如,從 std::sort 的 Compare
函式物件或從 std::make_shared 中 T
的建構函式)丟擲異常,則該異常將未經修改地傳播給呼叫者。
[編輯] 異常物件
雖然任何完整型別的物件和指向 void 的 cv 指標都可以作為異常物件丟擲,但所有標準庫函式都透過值丟擲未命名物件,並且這些物件的型別直接或間接派生自 std::exception。使用者定義的異常通常遵循此模式。[7][8][9]
為避免不必要的異常物件複製和物件切片,處理程式的最佳實踐是透過引用捕獲。[10][11][12][13]
[編輯] 注意
功能測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__cpp_constexpr_exceptions |
202411L |
(C++26) | constexpr 異常 |
[編輯] 外部連結
|