catch 子句可採三種參數形式:指標、傳值、傳參考。理論上指標效率最高 (無拷貝),但實務上強烈建議統一使用傳參考。
void someFunction() {
Exception ex; // 區域物件
throw &ex; // 拋出指標 → 物件離開作用域即被解構
}
catch (Exception* p) { } // 接收到懸空指標!未定義行為
程式設計師極易誤用區域物件。雖可用 static 或 new 解決,但引入新問題。
throw new Exception; // 堆上配置
catch (Exception* p) { delete p; } // 需刪除?
new 出來的 → 必須刪除,否則洩漏。catch 端無法分辨 來源,進退維谷。bad_alloc, bad_cast, bad_typeid, bad_exception) 皆為物件而非指標,指標捕獲無法處理它們。
catch (Widget w) 再拷貝一次 → 兩次拷貝建構/解構。
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" ✓
catch (ExceptionType& e) 或 catch (const ExceptionType& e)。std::exception 時同樣用參考。catch (...),且應立即重新拋出或轉換為具體類型。「Catch exceptions by reference!」—— 這條鐵律能省去無數除錯時光,是 C++ 異常處理的基石習慣。