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

More Effective C++:為什麼必須用引用捕獲異常

     編輯:關於C++

三種捕獲方式的抉擇

catch 子句可採三種參數形式:指標、傳值、傳參考。理論上指標效率最高 (無拷貝),但實務上強烈建議統一使用傳參考。

為什麼不用指標捕獲?

1. 物件生命週期難以保證


void someFunction() {
    Exception ex;           // 區域物件
    throw &ex;              // 拋出指標 → 物件離開作用域即被解構
}
catch (Exception* p) { }    // 接收到懸空指標!未定義行為

程式設計師極易誤用區域物件。雖可用 static 或 new 解決,但引入新問題。

2. 刪除責任模糊 (哈姆雷特困境)


throw new Exception; // 堆上配置
catch (Exception* p) { delete p; } // 需刪除?
  • 若拋出的是全域/靜態物件指標 → 不可刪除。
  • 若拋出的是 new 出來的 → 必須刪除,否則洩漏。
  • catch 端無法分辨 來源,進退維谷。

3. 違背標準庫異常設計

標準異常 (bad_alloc, bad_cast, bad_typeid, bad_exception) 皆為物件而非指標,指標捕獲無法處理它們。

為什麼不用傳值捕獲?

1. 雙重拷貝開銷

異常傳遞機制已拷貝一次暫時物件,catch (Widget w) 再拷貝一次 → 兩次拷貝建構/解構。

2. 物件切割 — 多態失效


class Exception { virtual const char* what() { return "base"; } };
class ValidationError : public Exception { 
    virtual const char* what() { return "validation"; } 
};

throw ValidationError();
catch (Exception ex) { cout << ex.what(); } // 輸出 "base"!切割發生

傳值捕獲導致衍生類部分被切除,虛擬函數調用解析為基類版本,多態行為徹底失效。

傳參考捕獲:完美解決所有問題


catch (Exception& ex) { cout << ex.what(); } // 輸出 "validation" ✓
  • 無刪除困擾: 參考不涉及所有權。
  • 無切割: 參考綁定完整暫時物件,虛擬函數正常動態綁定。
  • 支援標準異常: 可捕獲所有標準異常類別。
  • 僅一次拷貝: 僅異常機制產生的暫時物件,無額外拷貝。

實務建議

  1. 永遠使用 catch (ExceptionType& e) 或 catch (const ExceptionType& e)。
  2. 捕獲標準異常基類 std::exception 時同樣用參考。
  3. 只在極少數需攔截所有異常處理時用 catch (...),且應立即重新拋出或轉換為具體類型。

「Catch exceptions by reference!」—— 這條鐵律能省去無數除錯時光,是 C++ 異常處理的基石習慣。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved