57

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.

コンパイラはいつものように正しいですか? この問題について標準は何と言っていますか?

4

6 に答える 6

75

スタックが巻き戻される前に未処理の例外の terminate() が呼び出されるため、デストラクタは呼び出されません。

C++ 仕様の具体的な詳細は私の知識外ですが、gdb と g++ を使用したデバッグ トレースはこれを裏付けているようです。

ドラフト標準セクション 15.3 の箇条書き 9によると:

9 プログラム内に一致するハンドラーが見つからない場合、関数 terminate()
  (_except.terminate_) が呼び出されます。スタックが巻き戻されているかどうか
  terminate() を呼び出す前は実装定義です。
于 2008-10-21T15:04:37.310 に答える
18
于 2008-10-22T12:19:54.630 に答える
3

申し訳ありませんが、標準のコピーを持っていません。
私は間違いなくこれに対する決定的な答えが欲しいので、標準のコピーを持っている誰かが、何が起こっているかについての章と節を共有したいと思っています:

私の理解では、terminate は iff と呼ばれるだけです:

  • 例外処理メカニズムは、スローされた例外のハンドラーを見つけることができません。
    以下は、これのより具体的なケースです。
    • スタックの巻き戻し中に、例外がデストラクタをエスケープします。
    • スローされた式、例外はコンストラクターをエスケープします。
    • 例外は、ローカル以外の静的 (つまり、グローバル) のコンストラクター/デストラクターをエスケープします。
    • 例外は、atexit() で登録された関数をエスケープします。
    • 例外は main() をエスケープします
  • 例外が現在伝播されていないときに、例外を再スローしようとしています。
  • 予期しない例外は、例外指定子を使用して関数をエスケープします (予期しないものを介して)
于 2008-10-21T15:49:32.477 に答える
2

2 番目の例では、try{} ブロックを離れるときに dtor が呼び出されます。

最初の例では、プログラムが main() 関数を離れた後にシャットダウンするときに dtor が呼び出されます --- その時点で cout はすでに破棄されている可能性があります。

于 2008-10-21T14:58:30.567 に答える
2

また、参照されていないため、コンパイラは「a」に関連するコードを生成しないと想定しましたが、それでも、デストラクタが実行する必要があることを行うため、これは正しい動作ではありません。

だから、VS2008/vc9 (+SP1)、デバッグとリリースで試してみました。例外がスローされた後に ~A が呼び出され、f() から抜け出します - 私が正しければ、それは正しい動作です。

今、VS2005/vc8 (+SP1) で試してみましたが、同じ動作です。

確実にするためにブレークポイントを使用しました。コンソールで確認したところ、「〜A」メッセージもあります。もしかしてどこかで間違えた?

于 2008-10-21T15:02:25.940 に答える
2

この質問は簡単にグーグルで検索できるので、ここで私の状況を共有します。

例外が境界を越えていないことextern "C"、または MSVC オプション /EHs を使用していないことを確認してください (C++ 例外を有効にする = Extern C 関数 (/EHs) ではい)

于 2016-05-11T13:52:46.623 に答える