langShift

錯誤處理和例外

錯誤處理是穩健軟體開發的關鍵環節。C++ 透過例外提供強大的錯誤處理機制,允許將錯誤處理程式碼與正常程式邏輯分離。這與 JavaScript 更常見的傳回值和用於非同步操作的 try...catch 區塊有顯著不同。

例外處理機制 (try-catch-throw)

在 C++ 中,例外用於發出和處理程式執行期間發生的異常情況或錯誤。例外處理的核心組件是:

  • throw 用於發出異常情況。當錯誤發生時,會 throw 一個例外。
  • try 區塊: 可能發生例外的程式碼區塊。此區塊內的程式碼會受到監控,以偵測例外。
  • catch 區塊: 處理特定類型例外的程式碼區塊。如果在 try 區塊內拋出例外,程式會跳轉到適當的 catch 區塊。
正在加载...

例外安全保證

在設計可能拋出例外的函式時,考慮例外安全保證非常重要。這些保證描述了如果拋出例外時程式的狀態:

  1. 不拋出保證 (最強): 函式永遠不會拋出例外。
  2. 強保證: 如果拋出例外,程式的狀態保持不變(就像從未呼叫過函式一樣)。
  3. 基本保證: 如果拋出例外,程式保持在有效狀態,但確切狀態未指定。
  4. 無保證 (最弱): 如果拋出例外,對程式狀態沒有任何保證。

錯誤碼 vs. 例外

歷史上,C 語言風格的程式設計通常使用錯誤碼(傳回特殊值以指示錯誤)進行錯誤處理。雖然簡單,但這種方法可能導致程式碼冗長且容易忽略錯誤。

例外在現代 C++ 中通常用於異常情況,因為:

  • 它們將錯誤處理邏輯與正常程式碼流程分離。
  • 它們沿著呼叫堆疊傳播,直到被捕獲,防止錯誤被忽略。
  • 它們可以攜帶更多關於錯誤的資訊。

RAII (資源取得即初始化) 資源管理

RAII 是 C++ 中用於安全管理資源(如記憶體、檔案句柄、網路連線)的基本慣用語。它指出資源取得應在建構函式中發生,資源釋放應在解構函式中發生。當物件超出作用域時(無論是正常情況還是由於例外),其解構函式都會自動呼叫,確保資源得到正確清理。

這對於例外尤其重要,因為它保證即使例外繞過正常函式退出點,資源也能得到釋放。

正在加载...

與 JavaScript 錯誤處理的比較

JavaScript 主要使用 Error 物件和 try...catch 區塊進行同步錯誤處理。對於非同步操作,Promise 和 async/awaittry...catch 結合使用很常見。

特性JavaScriptC++
機制Error 物件、throwtry...catch例外 (throwtry...catch)
資源管理自動 (GC)、finally 用於明確清理手動、RAII (資源取得即初始化)
錯誤類型內建 Error 類型 (例如,TypeErrorReferenceError)、自訂 Error 子類別標準例外 (std::runtime_errorstd::bad_alloc)、自訂例外類別
傳播沿著呼叫堆疊傳播直到被捕獲沿著呼叫堆疊傳播直到被捕獲
性能對於簡單錯誤通常開銷較小如果例外頻繁拋出,可能會產生性能開銷 (由於堆疊展開)

例外處理最佳實踐

  1. 按值拋出,按引用捕獲: 將例外作為物件拋出(按值),並按常數引用捕獲(const std::exception&const MyException&)。這可以避免切片和不必要的複製。
  2. 先捕獲特定例外: 在更通用的例外類型之前捕獲更特定的例外類型。
  3. 使用 std::exception 階層:std::exception 或其子類別(例如,std::runtime_errorstd::logic_error)衍生自訂例外類別。
  4. 避免在解構函式中拋出: 從解構函式中拋出例外可能導致 std::terminate,如果另一個例外已經活躍。
  5. 將例外用於異常情況: 不要將例外用於正常程式流程或預期情況。例如,不要使用例外來表示使用者輸入了無效輸入;而是使用驗證和傳回值。
  6. RAII 是關鍵: 利用 RAII 確保資源清理,即使發生例外。

常見例外處理陷阱

  • 按值捕獲: 如果按基底類別類型捕獲衍生例外,可能導致物件切片。
  • 忽略例外: 不捕獲例外可能導致程式終止。
  • 過度使用例外: 將例外用於非異常情況可能會損害性能並使程式碼難以閱讀。
  • 未處理所有例外: 通用 catch (...) 可以作為最後的手段,但特定處理程式更好。

練習題:

  1. 描述 C++ 例外處理中的 trycatchthrow 關鍵字。它們如何協同工作來管理錯誤?
  2. 什麼是 RAII,為什麼它被認為是 C++ 中資源管理的基本慣用語?提供一個範例,說明 RAII 如何幫助確保資源清理,即使發生例外。
  3. 比較和對比 C++ 的例外處理機制與 JavaScript 的錯誤處理。它們在方法上的主要差異是什麼?

專案構想:

  • 建立一個簡單的 C++ 程式,模擬檔案處理工具。實作可能失敗的函式(例如,openFilereadFilewriteFile)。使用 C++ 例外處理檔案未找到、權限被拒絕或磁碟已滿等錯誤。確保所有資源(檔案句柄)都使用 RAII 原則正確關閉,即使發生例外。