24

次のコードでは、スタックベースの変数 'ex' がスローされ、ex が宣言されたスコープ外の関数でキャッチされます。(AFAIK)スタックベースの変数は、宣言されたスコープ外では使用できないため(スタックが巻き戻されているため)、これは私には少し奇妙に思えます。

void f() {
    SomeKindOfException ex(...);
    throw ex;
}

void g() {
    try {
        f();
    } catch (SomeKindOfException& ex) {
        //Handling code...
    }
}

SomeKindOfException のデストラクタに print ステートメントを追加しました。ex は f() でスコープ外になると破壊されますが、g() でキャッチされ、スコープ外になると再び破壊されることが示されています。

何か助けはありますか?

4

6 に答える 6

21

例外オブジェクトは、スタックの巻き戻し後も生き残るために特別な場所にコピーされます。2 つの破棄が表示される理由は、f() を終了すると元の例外が破棄され、g() を終了するとコピーが破棄されるためです。

于 2010-03-08T20:04:41.043 に答える
10

C++ 標準 15.1/4:

スローされる例外の一時コピー用のメモリは、3.7.3.1 で説明されている場合を除き、特定されていない方法で割り当てられます。その例外に対して実行されているハンドラーがある限り、一時的なものは持続します。特に、ハンドラーが throw を実行して終了する場合。このステートメントは、同じ例外の別のハンドラーに制御を渡すため、一時的なものは残ります。例外に対して実行されていた最後のハンドラーが、throw 以外の方法で終了したとき。一時オブジェクトが破棄され、実装によって一時オブジェクトのメモリの割り当てが解除される場合があります。そのような割り当て解除は、不特定の方法で行われます。破棄は、ハンドラーの例外宣言で宣言されたオブジェクトの破棄の直後に発生します。

これ以上言うことはありません。

于 2010-03-08T20:14:15.160 に答える
10

オブジェクトは、スタックの巻き戻し後も存続する例外オブジェクトにコピーされます。そのオブジェクトのメモリがどこから来るのかは特定されていません。大きなオブジェクトの場合はおそらくmalloc'ed になり、小さなオブジェクトの場合、実装には事前に割り当てられたバッファーが含まれる可能性があります (これが例外に使用される可能性があると想像できbad_allocます)。

次に、参照はその例外オブジェクトexにバインドされます。これは一時的なものです (名前はありません)。

于 2010-03-08T20:05:14.630 に答える
6

ex をスローすると、スローされた例外オブジェクトに使用される特別なメモリ位置にコピーされます。このようなコピーは、通常のコピー コンストラクターによって実行されます。

これは、次の例から簡単に確認できます。

#include <iostream>

void ThrowIt();

class TestException
{
  public:
    TestException()
    {
        std::cerr<<this<<" - inside default constructor"<<std::endl;
    }

    TestException(const TestException & Right)
    {
        (void)Right;
        std::cerr<<this<<" - inside copy constructor"<<std::endl;
    }

    ~TestException()
    {
        std::cerr<<this<<" - inside destructor"<<std::endl;    
    }
};

int main()
{
    try
    {
        ThrowIt();
    }
    catch(TestException & ex)
    {
        std::cout<<"Caught exception ("<<&ex<<")"<<std::endl;
    }
    return 0;
}

void ThrowIt()
{
    TestException ex;
    throw ex;
}

出力例:

matteo@teolapubuntu:~/cpp/test$ g++ -O3 -Wall -Wextra -ansi -pedantic ExceptionStack.cpp -o ExceptionStack.x
matteo@teolapubuntu:~/cpp/test$ ./ExceptionStack.x 
0xbf8e202f - inside default constructor
0x9ec0068 - inside copy constructor
0xbf8e202f - inside destructor
Caught exception (0x9ec0068)
0x9ec0068 - inside destructor

ちなみに、ここで、スローされたオブジェクト (0x09ec0068) に使用されたメモリの場所が、元のオブジェクト (0xbf8e202f) のメモリの場所から離れていることがわかります。スローされたオブジェクトは、仮想アドレス空間でかなりダウンしています。それでも、これは実装の詳細です。他の回答が指摘したように、標準では、スローされたオブジェクトのメモリをどこに配置し、どのように割り当てる必要があるかについて何も述べていません。

于 2010-03-08T20:15:43.893 に答える
4

標準が 15.1/4 で述べていること (「例外処理/例外のスロー」) に加えて、スローされる例外の一時コピー用のメモリが不特定の方法で割り当てられるということです。割り当てられる例外オブジェクトは次のとおりです。

  • 標準の 3.7.3.1/4 (「割り当て関数」) は、new式または「グローバル割り当て関数」への呼び出し (つまり、operator new()置換) によって例外オブジェクトを割り当てることができないことを示しています。malloc()標準で定義されている「グローバル割り当て関数」ではないことに注意してください。したがってmalloc()、例外オブジェクトを割り当てるためのオプションであることは間違いありません。

  • 「例外がスローされると、例外オブジェクトが作成され、通常、ある種の例外データ スタックに配置されます」(Stanley Lippman、「C++ オブジェクト モデルの内部」 - 7.2 例外処理)。

  • Stroustrup の「The C++ Programming Language, 3rd Edition」より: 「C++ 実装には、メモリ不足の場合にスローできる十分な予備メモリが必要ですbad_alloc。ただし、他の例外をスローすると、メモリが枯渇する可能性があります。」 (14.4.5 リソースの枯渇); そして、「実装は、例外を格納および送信するためのさまざまな戦略を適用できます。ただし、new標準のメモリ不足例外をスローできる十分なメモリがあることが保証されていますbad_alloc」 (14.3 例外のキャッチ)。

Stroustrup からの引用は事前標準であることに注意してください。Stroustrup が 2 回言及するほど重要であると考えたことを標準が保証していないように見えることは興味深いと思います。

于 2010-03-09T09:00:02.543 に答える
1

仕様に明示的に記載されているため、throwオペランドの代わりに一時オブジェクトが作成されます。

于 2010-03-08T20:10:04.277 に答える