錯誤處理和例外
錯誤處理是穩健軟體開發的關鍵環節。C++ 透過例外提供強大的錯誤處理機制,允許將錯誤處理程式碼與正常程式邏輯分離。這與 JavaScript 更常見的傳回值和用於非同步操作的 try...catch
區塊有顯著不同。
例外處理機制 (try-catch-throw
)
在 C++ 中,例外用於發出和處理程式執行期間發生的異常情況或錯誤。例外處理的核心組件是:
throw
: 用於發出異常情況。當錯誤發生時,會throw
一個例外。try
區塊: 可能發生例外的程式碼區塊。此區塊內的程式碼會受到監控,以偵測例外。catch
區塊: 處理特定類型例外的程式碼區塊。如果在try
區塊內拋出例外,程式會跳轉到適當的catch
區塊。
正在加载...
例外安全保證
在設計可能拋出例外的函式時,考慮例外安全保證非常重要。這些保證描述了如果拋出例外時程式的狀態:
- 不拋出保證 (最強): 函式永遠不會拋出例外。
- 強保證: 如果拋出例外,程式的狀態保持不變(就像從未呼叫過函式一樣)。
- 基本保證: 如果拋出例外,程式保持在有效狀態,但確切狀態未指定。
- 無保證 (最弱): 如果拋出例外,對程式狀態沒有任何保證。
錯誤碼 vs. 例外
歷史上,C 語言風格的程式設計通常使用錯誤碼(傳回特殊值以指示錯誤)進行錯誤處理。雖然簡單,但這種方法可能導致程式碼冗長且容易忽略錯誤。
例外在現代 C++ 中通常用於異常情況,因為:
- 它們將錯誤處理邏輯與正常程式碼流程分離。
- 它們沿著呼叫堆疊傳播,直到被捕獲,防止錯誤被忽略。
- 它們可以攜帶更多關於錯誤的資訊。
RAII (資源取得即初始化) 資源管理
RAII 是 C++ 中用於安全管理資源(如記憶體、檔案句柄、網路連線)的基本慣用語。它指出資源取得應在建構函式中發生,資源釋放應在解構函式中發生。當物件超出作用域時(無論是正常情況還是由於例外),其解構函式都會自動呼叫,確保資源得到正確清理。
這對於例外尤其重要,因為它保證即使例外繞過正常函式退出點,資源也能得到釋放。
正在加载...
與 JavaScript 錯誤處理的比較
JavaScript 主要使用 Error
物件和 try...catch
區塊進行同步錯誤處理。對於非同步操作,Promise 和 async/await
與 try...catch
結合使用很常見。
特性 | JavaScript | C++ |
---|---|---|
機制 | Error 物件、throw 、try...catch | 例外 (throw 、try...catch ) |
資源管理 | 自動 (GC)、finally 用於明確清理 | 手動、RAII (資源取得即初始化) |
錯誤類型 | 內建 Error 類型 (例如,TypeError 、ReferenceError )、自訂 Error 子類別 | 標準例外 (std::runtime_error 、std::bad_alloc )、自訂例外類別 |
傳播 | 沿著呼叫堆疊傳播直到被捕獲 | 沿著呼叫堆疊傳播直到被捕獲 |
性能 | 對於簡單錯誤通常開銷較小 | 如果例外頻繁拋出,可能會產生性能開銷 (由於堆疊展開) |
例外處理最佳實踐
- 按值拋出,按引用捕獲: 將例外作為物件拋出(按值),並按常數引用捕獲(
const std::exception&
或const MyException&
)。這可以避免切片和不必要的複製。 - 先捕獲特定例外: 在更通用的例外類型之前捕獲更特定的例外類型。
- 使用
std::exception
階層: 從std::exception
或其子類別(例如,std::runtime_error
、std::logic_error
)衍生自訂例外類別。 - 避免在解構函式中拋出: 從解構函式中拋出例外可能導致
std::terminate
,如果另一個例外已經活躍。 - 將例外用於異常情況: 不要將例外用於正常程式流程或預期情況。例如,不要使用例外來表示使用者輸入了無效輸入;而是使用驗證和傳回值。
- RAII 是關鍵: 利用 RAII 確保資源清理,即使發生例外。
常見例外處理陷阱
- 按值捕獲: 如果按基底類別類型捕獲衍生例外,可能導致物件切片。
- 忽略例外: 不捕獲例外可能導致程式終止。
- 過度使用例外: 將例外用於非異常情況可能會損害性能並使程式碼難以閱讀。
- 未處理所有例外: 通用
catch (...)
可以作為最後的手段,但特定處理程式更好。
練習題:
- 描述 C++ 例外處理中的
try
、catch
和throw
關鍵字。它們如何協同工作來管理錯誤? - 什麼是 RAII,為什麼它被認為是 C++ 中資源管理的基本慣用語?提供一個範例,說明 RAII 如何幫助確保資源清理,即使發生例外。
- 比較和對比 C++ 的例外處理機制與 JavaScript 的錯誤處理。它們在方法上的主要差異是什麼?
專案構想:
- 建立一個簡單的 C++ 程式,模擬檔案處理工具。實作可能失敗的函式(例如,
openFile
、readFile
、writeFile
)。使用 C++ 例外處理檔案未找到、權限被拒絕或磁碟已滿等錯誤。確保所有資源(檔案句柄)都使用 RAII 原則正確關閉,即使發生例外。