2

以下のコードでは、名前のないA変数をのctorに渡すとB、その変数は行の後に破棄されます。この答えによると:

一時オブジェクトは、それらが含まれる完全な式の最後で破棄されます。完全な式は、他の式の部分式ではない式です。通常、これは; (or ) for if, while, switch etc.)ステートメントの終わりを示すことで終了することを意味します。

私はそれを取得しますが、それが破壊された後、クラスはどのようBにしてその変数の値を知ることができますか?のコピーコンストラクターがenverと呼ばれmamber_aていることを知っています。Aこれはどのように可能ですか?

#include <iostream>
using namespace std;

class A 
{
        int sign;
        A();
        const A & operator=(const A &);
public:
        A(int x) : sign(x) { 
                cout << "A ctor : " << sign << endl; 
        }

        void WriteA() const { 
                cout << sign << endl; 
        }

        ~A() { 
                cout << "A dtor : " << sign << endl; 
        }

        A(const A &) {
                cout << "A copied : " << sign << endl;
        }
};

class B
{
        int sign;
        const A & member_a;
public:
        B(const A & aa , int ww ) : sign (ww) ,member_a(aa) { 
                cout << "B ctor : " << sign << endl; 
        }

        void WriteB() const {
                cout << "Value of member_a :";
                member_a.WriteA();      
        } 

        ~B() { 
                cout << "B dtor : " << sign  << endl;
        }
};

int main() {
        A a(10);
        B b1(a,1);
        b1.WriteB();     

        B b2(A(20),2);
        b2.WriteB();

        return 0;
}

出力は次のとおりです。

A ctor : 10
B ctor : 1
Value of member_a :10
A ctor : 20
B ctor : 2
A dtor : 20
Value of member_a :20 // Object A was destructed. Where does this 20 come from?
B dtor : 2
B dtor : 1
A dtor : 10
4

2 に答える 2

5

あなたはC++のトリッキーな部分の1つを持っています

member_aの値が20である可能性は非常に高いです。未定義動作と呼ばれるものにぶつかっています。

クラスが外部オブジェクトへの参照を保持する場合、オブジェクトの存続期間が参照されているオブジェクトよりも長く続くことを確認するのはプログラマーの責任です。この場合、オブジェクトを呼び出すmember_a.WriteA();と、オブジェクトはすでに破棄されているため、自分のものではない可能性のあるメモリにアクセスしています(この場合、オブジェクトは、(完全に偶然に)オーバーライドされていない近くの場所にあるだけです) 。

オブジェクトへの参照を保持する場合。const参照を保持することはできますが、一時的な値を誤って渡さないように、パラメーターを通常の参照にするのが最適な場合があります(constオブジェクトを参照で渡す必要がある場合があるため、これは常に機能するとは限りません)。

于 2011-03-19T21:10:26.030 に答える
1

破壊されたオブジェクトへの参照を使用することは、「未定義の動作」です。

A のデストラクタで、"sign" を "-1" に設定してみて、どうなるか見てみましょう。おそらく、「WriteB」を呼び出すと、死亡したオブジェクトにメッセージを送信したことが示されます。

次に、b2 のコンストラクターと b2.WriteB の呼び出し (サブルーチンの呼び出しなど) の間に、コードを使用して多数のスタックを配置してみてください。おそらく、呼び出しが何か違うものを出力することに気付くでしょう。

于 2011-03-19T21:22:41.327 に答える