簡體   English   中英

為什么在異常時不調用析構函數?

[英]Why destructor is not called on exception?

我希望在這個程序中調用A::~A() ,但它不是:

#include <iostream>

struct A {
  ~A() { std::cout << "~A()" << std::endl; }
};

void f() {
  A a;
  throw "spam";
}

int main() { f(); }

但是,如果我將最后一行更改為

int main() try { f(); } catch (...) { throw; }

然后A::~A()調用。

我正在使用 Visual Studio 2005 的“Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86”進行編譯。命令行是cl /EHa my.cpp

編譯器正常嗎? 標准在這件事上是怎么說的?

析構函數沒有被調用,因為在堆棧展開之前調用了未處理異常的 terminate()。

C++ 規范所說的具體細節超出了我的知識范圍,但 gdb 和 g++ 的調試跟蹤似乎證實了這一點。

根據標准草案第 15.3第 9 條:

9 If no matching handler is found in a program, the function terminate()
  (_except.terminate_)  is  called.  Whether or not the stack is unwound
  before calling terminate() is implementation-defined.

C++ 語言規范指出:為在從 try 塊到 throw 表達式的路徑上構造的自動對象調用析構函數的過程稱為“堆棧展開”。 您的原始代碼不包含 try 塊,這就是不會發生堆棧展開的原因。

抱歉,我沒有標准的副本。
我肯定想要一個明確的答案,所以有標准副本的人想要分享關於正在發生的事情的章節:

根據我的理解,終止僅稱為 iff:

  • 異常處理機制找不到拋出異常的處理程序。
    以下是更具體的案例:
    • 在堆棧展開期間,異常會轉義析構函數。
    • 一個拋出的表達式,一個異常轉義構造函數。
    • 異常轉義非局部靜態(即全局)的構造函數/析構函數
    • 異常轉義使用 atexit() 注冊的函數。
    • 一個異常轉義 main()
  • 在當前沒有異常傳播時嘗試重新拋出異常。
  • 意外異常轉義帶有異常說明符的函數(通過意外)

在第二個示例中,dtor 在離開 try{} 塊時被調用。

在第一個示例中,當程序在離開 main() 函數后關閉時調用 dtor ---此時 cout 可能已經被銷毀。

我也假設編譯器不會生成相對於“a”的代碼,因為它沒有被引用,但仍然不是正確的行為,因為析構函數做了一些必須執行的事情。

因此,我在 VS2008/vc9 (+SP1) 中嘗試了調試和發布,並在拋出異常后調用 ~A,退出 f() - 如果我是對的,這是正確的行為。

現在我只是嘗試使用 VS2005/vc8 (+SP1) 並且它的行為相同。

我使用斷點來確定。 我剛剛檢查了控制台,我也收到了“~A”消息。 也許你在其他地方做錯了?

這個問題很容易用谷歌搜索,所以我在這里分享我的情況。

確保您的例外不跨越extern "C"邊界或使用 MSVC 選項 /EHs(Enable C++ exeptions = Yes with Extern C functions (/EHs))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM