デストラクタが例外で呼び出されないのはなぜですか?
-
03-07-2019 - |
質問
このプログラムで 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; }
then A ::〜A()
が呼び出されます。
「Microsoft(R)32-bit C / C ++ Optimizing Compiler Version 14.00.50727.762 for 80x86」でコンパイルしていますVisual Studio 2005から。コマンドラインは cl / EHa my.cpp
です。
コンパイラはいつもどおりですか?この件に関して標準は何と言っていますか?
解決
スタックが巻き戻される前に未処理の例外のterminate()が呼び出されるため、デストラクタは呼び出されません。
C ++仕様の詳細は私の知る範囲外ですが、gdbとg ++のデバッグトレースはこれを裏付けているようです。
ドラフト標準セクション15.3 bullet 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-expressionへのパス上に構築された自動オブジェクトのデストラクタを呼び出すプロセスは、&#8220; stack unwinding。&#8221; と呼ばれます 元のコードにはtryブロックが含まれていないため、スタックの巻き戻しは行われません。
コンパイラも&a;に関連するコードを生成しないと仮定しました。参照されていないが、それでも、デストラクタが実行する必要がある処理を行うため、正しい動作ではありません。
だから、VS2008 / vc9(+ SP1)で試し、デバッグとリリースを行い、例外がスローされた後に〜Aが呼び出され、f()から抜け出します-それが正しい場合は正しい動作です。
今、VS2005 / vc8(+ SP1)で試しましたが、同じ動作です。
念のためブレークポイントを使用しました。コンソールで確認したところ、「〜A」があります。メッセージも。たぶんあなたはどこか間違ったことをしましたか?
申し訳ありませんが、標準のコピーは手元にありません。
私は間違いなくこれに対する決定的な答えが欲しいので、標準のコピーを持っている人は何が起こっているかについて章と詩を共有したいです:
私の理解では、terminateはiffとのみ呼ばれます:
- 例外処理メカニズムは、スローされた例外のハンドラーを見つけることができません。
以下は、これのより具体的なケースです。- スタックの巻き戻し中、例外はデストラクタをエスケープします。
- スローされた式、例外はコンストラクターをエスケープします。
- 例外は、非ローカルスタティック(つまりグローバル)のコンストラクタ/デストラクタをエスケープします
- 例外は、atexit()で登録された関数をエスケープします。
- main()をエスケープする例外
- 現在伝播している例外がないときに例外を再スローしようとしています。
- 予期しない例外は、例外指定子を使用して関数をエスケープします(予期しない場合)
この質問は簡単にグーグルで検索できるため、ここで状況を共有します。
exorionが extern&quot; C&quot;
の境界を越えないことを確認するか、MSVCオプション/ EHsを使用します(Extern C関数(/ EHs)でC ++ exeptions = Yesを有効にします)
2番目の例では、dtorはtry {}ブロックを離れるときに呼び出されます。
最初の例では、main()関数を終了した後にプログラムがシャットダウンするときにdtorが呼び出されます。この時点までにcoutはすでに破棄されている可能性があります。