2

次のコードがあります。

#include <iostream>
#include <vector>
#include <tr1/memory>

struct FooError {};

struct Foo
{
    ~Foo() { std::cerr << "~Foo() executed" << std::endl; }
    explicit Foo(unsigned int index) { if (5 == index) throw FooError(index); };
};


int main() {
    typedef std::tr1::shared_ptr<Foo> FooPtr;
    std::vector<FooPtr> foos;
    for (unsigned int index = 0; index < 20; ++index)
    {
        try
        {
            foos.push_back(FooPtr(new Foo(index)));
        }
        catch (const FooError&)
        {
            std::cerr << "FooError caught" << std::endl;
        }
    }
}

ブロック~Foo()があるときに実行されるセットが表示されます。try{} catch{}例外ハンドラがない場合、何も出力されません。例外が処理されるときに、スタック割り当てオブジェクトのデストラクタが呼び出されるということですか? または、std::cerr バッファリングの問題のために何も出力されませんか?

4

4 に答える 4

5

以下は、C++03 標準から何が起こっているかの詳細です。

  • 15.3/9から例外処理

    プログラム内に一致するハンドラーが見つからない場合、関数 terminate() が呼び出されます。

  • 18.6.3 異常終了から:

    実装のデフォルトの terminate_handler は、abort() を呼び出します。

  • そして 3.6.3/4 終了から:

    void abort();で宣言された関数を呼び出す<cstdlib>と、自動または静的ストレージ期間のオブジェクトのデストラクタを実行せず、atexit() に渡された関数を呼び出すことなく、プログラムが終了します。

そのため、foosオブジェクトが破棄されていません (静的な保存期間があります)。ただし、ローカル変数 (自動継続時間を持つ) になるように変更しても、問題は解決しない可能性があります (強調を追加)。

したがって、static durationオブジェクトの場合、終了ハンドラーを変更しない限り、デストラクタは呼び出されません (おそらくexit()の代わりに呼び出す必要がありますabort())。ただし、自動オブジェクトの場合、問題が残る可能性があります (強調を追加)。

15.5.1/1terminate()関数

一致するハンドラーが見つからない状況では、 terminate() が呼び出される前にスタックがアンワインドされるかどうかは実装定義です。他のすべての状況では、terminate() が呼び出される前にスタックが巻き戻されてはなりません。

于 2011-12-18T19:04:37.663 に答える
3

通常の実行または try/throw/catch によるプログラムのスコープの巻き戻しは、アプリケーションが から戻って終了した場合にのみ発生しますmainabort()アプリケーションが例外を介して (またはまたはを介し​​てterminate()) 終了した場合、巻き戻しは行われず、デストラクタも呼び出されません。

これは、自動オブジェクトと静的オブジェクトの両方に関係します。

于 2011-12-18T17:27:09.783 に答える
1

例外をキャッチすると、メモリーをクリーンアップするためにデアロケーターが呼び出されます。例外をキャッチしないと、アプリケーションは終了します。

ちなみに、ベクトルは実際にはすべてのデータをヒープに格納します。そのため、サイズ変更可能です。スタック上のデータは、(隠されている) ヒープ上のメモリへのポインタであると考えることができます。

于 2011-12-18T17:20:56.030 に答える