delete。在析構函數內部,無法區分 當前是哪種情境,也無法得知是否已有其他例外處於作用中。因此必須保守假設:析構函數執行時可能正處於堆疊展開。
若析構函數拋出例外,且此時已有另一個例外正在傳播(即雙重例外),C++ 標準規定立即呼叫 std::terminate() 終止程式。terminate 預設呼叫 abort(),不會釋放區域物件、不會執行任何清理,直接強制結束進程。這是災難性後果。
class Session {
public:
~Session() { logDestruction(this); } // 危險!
private:
static void logDestruction(Session* addr);
};
若 logDestruction 拋出例外(如 I/O 錯誤),且此時正因其他錯誤展開堆疊,程式將瞬間終止。
Session::~Session() {
try {
logDestruction(this);
} catch (...) { } // 捕獲並忽略所有例外
}
catch(...) 空主體不是無動作,它阻斷例外傳播出析構函數。catch 內的記錄動作又拋出例外,也會導致 terminate,故必須確保 catch 區塊絕不拋出(必要時再套一層 try-catch 或使用不拋出生的 API)。若析構函數中途拋出例外,後續清理代碼(如釋放資源、提交交易)將不會執行。例如:
Session::~Session() {
logDestruction(this); // 若拋出
endTransaction(); // 此行永不執行 → 交易懸掛
}
即使調整順序,若 endTransaction 也可能拋出,仍需 try-catch 保護。
noexcept 的原因。Herb Sutter 指出:「拋出例外的析構函數是邪惡的」。遵循此規則,是寫出健壯 C++ 程式的基石。