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

C++ 異常處理機制全解析:try/catch/throw、自定義異常、標準異常體系、RAII 與棧展開

     編輯:關於C++

異常處理三大關鍵字

try {
    // 可能拋出異常的代碼
} catch (const ExceptionType1& e) {
    // 處理 ExceptionType1 及其派生類
} catch (const ExceptionType2& e) {
    // 處理 ExceptionType2
} catch (...) {
    // 捕獲所有其他異常(最後兜底)
}
  • throw expr:拋出異常對象(拷貝/移動構造到異常存儲區)
  • catch (Type name):按類型匹配,**派生類先於基類**捕獲
  • catch (...):捕獲任意類型,常用於日誌/清理後重拋

異常對象生命周期與棧展開

  1. 拋出點構造異常對象(複製/移動語義)
  2. **棧展開**:沿調用鏈向上銷毀所有**已構造完成**的局部對象(調用析構函數)
  3. 匹配 catch 子句,進入處理塊
  4. catch 結束後,異常對象銷毀
  5. 若無匹配 catch,調用 std::terminate

⚠️ **析構函數中不可拋出異常**(C++11 起隱含 noexcept),否則雙重異常導致 terminate。

標準異常體系 ()

std::exception
├── std::logic_error          // 邏輯錯誤(可預防)
│   ├── std::invalid_argument // 無效參數
│   ├── std::domain_error     // 域錯誤(數學)
│   ├── std::length_error     // 長度超限
│   └── std::out_of_range     // 越界
├── std::runtime_error        // 運行時錯誤(難預防)
│   ├── std::range_error      // 範圍錯誤
│   ├── std::overflow_error   // 上溢
│   └── std::underflow_error  // 下溢
├── std::bad_alloc            // new 失敗
├── std::bad_cast             // dynamic_cast 失敗
├── std::bad_typeid           // typeid 失敗
├── std::bad_exception        // unexpected_handler 拋出
└── std::ios_base::failure    // IO 流錯誤

所有標準異常提供 virtual const char* what() const noexcept 返回錯誤描述。

自定義異常類最佳實踐

class NetworkError : public std::runtime_error {
    int errorCode;
    std::string endpoint;
public:
    NetworkError(int code, const std::string& ep, const std::string& msg)
        : std::runtime_error(msg), errorCode(code), endpoint(ep) {}
    int code() const noexcept { return errorCode; }
    const std::string& endpoint() const noexcept { return endpoint; }
};

// 使用
void connect(const std::string& host) {
    if (!reachable(host))
        throw NetworkError(ETIMEDOUT, host, "Connection timeout");
}

原則:繼承 std::exception 或其派生類;提供豐富診斷信息;保證拷貝/移動構造不拋異常(noexcept)。

異常規範 (C++11 棄用動態規範)

void foo() noexcept;           // 承諾不拋出(違反 → terminate)
void bar() noexcept(false);    // 可能拋出(默認)
// C++17 noexcept 成為類型系統一部分:noexcept(foo()) 為常量表達式

重新拋出與異常傳遞

try {
    risky();
} catch (const NetworkError& e) {
    log(e);
    if (!canRecover(e)) throw; // 原封不動重拋,保持類型與棧跡蹤
}

異常安全性保證等級

等級保證典型實現
無保證可能洩漏資源、破壞不變量裸指針手動管理
基本保證不洩漏資源、對象保持有效狀態(但狀態可能改變)智能指針、RAII
強保證操作要么成功要么回滾到原狀態(事務語義)Copy-and-swap、事務日誌
不拋出保證絕不拋出異常析構函數、swap、移動操作

RAII 與資源管理

核心思想:資源獲取即初始化,析構函數釋放資源。棧展開自動調用析構,**天然實現異常安全**。

void processFile(const std::string& path) {
    std::ifstream in(path); // 構造打開,析構自動關閉
    std::unique_ptr buf = std::make_unique(1024);
    // 任何拋出異常,in/buf 確定釋放
    parse(in, *buf);
}

性能與工程考量

  • 零開銷原則:不拋出異常時無額外開銷;拋出時棧展開開銷較大(非熱路徑可接受)
  • 錯誤碼 vs 異常:預期頻發錯誤(如解析失敗)用 std::expected/錯誤碼;不可預期/嚴重錯誤用異常
  • 跨 DLL/異步邊界:異常不可跨越 C 接口/線程邊界,需在邊界捕獲轉換
  • 異常說明文檔化:函數註釋列出可能拋出的異常類型

C++20/23 新特性

  • std::source_location:捕獲文件/行/函數信息,豐富異常上下文
  • std::exception_ptr:跨線程傳遞異常
  • std::expected<T, E> (C++23):無異常錯誤處理單子
  • noexcept 推導改進、模板異常規範
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved