2012-07-01 10 views
7

私はスローされたオブジェクトがメモリにどこに格納されているのか把握したい。投げられたオブジェクトはどこにありますか?

#include <iostream> 

#define print_dist() int a;\ 
    do { std::cout << __FUNCTION__ << "() a[" << (long)&a - (long)ptrMainStackBase << "]" << std::endl; } while (0) 

#define print_distx(x) \ 
    do { std::cout << __FUNCTION__ << "() " #x "[" << (long)&x - (long)ptrMainStackBase << "]" << std::endl; } while (0) 

#define print_distxy(x, y) \ 
    do { std::cout << __FUNCTION__ << "() " #x "(ex)[" << (long)&x - (long)y << "]" << std::endl; } while (0) 

class CTest 
{ 
    public: 
     CTest() 
     { std::cout << "CTest::CTest" << std::endl; } 

// private: 
     CTest(const CTest&) 
     { std::cout << "copy" << std::endl; } 
}; 
const CTest *ptrException; 
int *ptrMainStackBase; 

void Test2() 
{ 
    print_dist(); 
    CTest test; 
    print_distx(test); 
    std::cout << "&test=" << &test << std::endl; 
    throw test; 
} 

void Test1() 
{ 
    print_dist(); 
    try 
    { 
     Test2(); 
    } 
    catch (const CTest& test) 
    { 
     ptrException = &test; 
     print_dist(); 
     print_distx(test); 
     print_distxy(test, ptrException); 
     std::cout << "&test=" << &test << std::endl; 
     throw test; 
    } 
} 

int main() 
{ 
    int b; 
    ptrMainStackBase = &b; 
    print_dist(); 
    try 
    { 
     print_dist(); 
     Test1(); 
    } 
    catch (const CTest& test) 
    { 
     print_dist(); 
     print_distx(test); 
     print_distxy(test, ptrException); 
     std::cout << "&test=" << &test << std::endl; 
    } 

    return 0; 
} 

をし、それが印刷します:だから私はそれのための小さなプログラムを書いた

main() a[-4] 
main() a[-8] 
Test1() a[-64] 
Test2() a[-104] 
CTest::CTest 
Test2() test[-108] 
&test=0x7fffd3b21628 <- test created here on stack 
copy 
Test1() a[-68] 
Test1() test[-140736732956164] 
Test1() test(ex)[0] 
&test=0xb89090 <- and copied here 
copy 
main() a[-12] 
main() test[-140736732956020] 
main() test(ex)[144] 
&test=0xb89120 <- and here 

私は、オブジェクトを投げるとき、それは最初から遠く離れた別のスタックにコピーされ、同じように見えます普通のもの。これは本当ですか?なぜ、2つの "例外スタックフレーム"の間に144バイトの距離があるのですか?

答えて

6

オブジェクトをスローすると、最初に一時的な場所にコピーされます。それ以外の場合は、スタックをアンロールすると範囲外になります。参照することにより、それをキャッチがそうのように、未定義の動作に生じるであろう:

void foo() { 
    A a; 
    throw a; 
} 

void bar() { 
    try { 
     foo(); 
    } catch (A& a) { 
     // use a 
    } 
} 

aない限りは、いくつかの一時的な場所にコピーされていた、あなたは、もはやcatchに存在する変数への参照を持っていると思います。これを行うには、Aにはパブリックコピーコンストラクタが必要です(VSを使用している場合を除き、この場合はit will use a private one as well...)。また、これは参考にするのが良い理由です。そうでない場合は、1つではなく2つのコピー構成があります。

+0

私はそれを信じることができません!私は、投げられたオブジェクトを参照することで捕まえるのが普通だと思います。 –

+0

@工業用抗うつ薬、それはあります。それは投げられた物がコピーされているので完全に安全です。コピーされていなければ問題があります。 – eran

2

私はオブジェクトをスローすると、まず最初にオブジェクトをスローすると、通常のオブジェクトからはるか遠い他のスタックにコピーされます。これは本当ですか?

例外がキャッチされたときにスローされたtestは存在しません。元のtestはすでに破壊されています。したがって、コピーでなければならず、引数やローカル変数とは別に新しいオブジェクトを管理する必要があります。言い換えれば、スタック上にではありません。

どこに住んでいますか?それは実装までです。ほとんどの場合、実装が管理する動的メモリ(ヒープなど)です。

2つの「例外スタックフレーム」の間に144バイトの距離があるのはなぜですか?

標準では、catchブロックで再スローされたときの例外の処理方法については言及していません。ローカル変数のthrowは必ずコピーを作成する必要があるため、throwを実装する最も簡単な方法は、常にコピーを作成することです。

+0

それはまた非常に良い答えですが、私は1つしか選択できません –

関連する問題