2

私は次のコードを持っています

#include <iostream>
using namespace std;

class Object {

public:
   Object(int id){
     cout << "Construct(" << id << ")" << endl; 
     m_id = id;       
   }

   Object(const Object& obj){
      cout << "Copy-construct(" << obj.m_id << ")" << endl;  
      m_id = obj.m_id;
   }

   Object& operator=(const Object& obj){
      cout << m_id << " = " << obj.m_id << endl; 
      m_id = obj.m_id;
      return *this; 
   }

   ~Object(){
       cout << "Destruct(" << m_id << ")" << endl; 
   }
private:
   int m_id;

};

Object func(Object var) { return var; }

int main(){
   Object v1(1);
   cout << "( a )" << endl;
   Object v2(2);
   v2 = v1;
   cout << "( b )" << endl;
   Object v4 = v1;
   Object *pv5;
   pv5 = &v1;
   pv5 = new Object(5);
   cout << "( c )" << endl;
   func(v1);
   cout << "( d )" << endl;
   delete pv5;
}

どの出力

Construct(1)
( a )
Construct(2)
2 = 1
( b )
Copy-construct(1)
Construct(5)
( c )
Copy-construct(1)
Copy-construct(1)
Destruct(1)
Destruct(1)
( d )
Destruct(5)
Destruct(1)
Destruct(1)
Destruct(1)

Object v4 = v1;これにはいくつか問題があります。まず、コピーコンストラクターを呼び出してCopy-construct(1)、の印刷後に生成するのはなぜですか( b )

また、コピーコンストラクターの印刷( c )が再び2回呼び出された後、この関数がどのように機能してそれを生成するのかわかりません。 Object func(Object var) { return var; }

そしてその直後に Destruct(1)2回呼び出されてから( d )印刷されます。

長い質問でごめんなさい、私は上記と混同しています。

4

3 に答える 3

5
Object v1(1);
// Construct(1)

通常のコンストラクターは、自動スタック変数を呼び出します(関数の最後で破棄されます)。

cout << "( a )" << endl;
// ( a )

Object v2(2);
// Construct(2)

別のコンストラクター呼び出し。

v2 = v1;
// 2 = 1

代入演算子が呼び出されるのは、v2がすでに作成されており(コンストラクターを呼び出したため)、現在、ある既存のオブジェクトを別のオブジェクトに代入しているためです。

cout << "( b )" << endl;
// ( b )

Object v4 = v1;
// Copy-construct(1)

Object v4はまだ作成されていないため、ここではコピーコンストラクターが呼び出されます。そのため、v1のコピーとして作成します。ここでの割り当ては、あなたが行ったのと同じ意味で解釈されますObject v4(v1)

Object *pv5;
pv5 = &v1;
pv5 = new Object(5);
// Construct(5)

ヒープオブジェクトのコンストラクターを呼び出します(で明示的に破棄されますdelete)。

cout << "( c )" << endl;
// ( c )

func(v1);
// Copy-construct(1) <br />
// Copy-construct(1) <br />
// Destruct(1) <br />
// Destruct(1) <br />

コピーコンストラクターが最初に呼び出され、v1がパラメーターvarにコピーされます。呼び出し元への戻り値としてvarのコピーを作成するために再度呼び出されます。varは、関数を終了するときにスタックからポップされるため、破棄されます。戻り値は、式func(v1)の後で破棄されます。

cout << "( d )" << endl;
// ( d )

delete pv5;
// Destruct(5)

pv5が指すオブジェクトは手動で破棄されます。

} // end of main
// Destruct(1) <br />
// Destruct(1) <br />
// Destruct(1) <br />

自動変数v1、v2、v4(すべて割り当てまたはコピー構築のいずれかからv1のIDをコピーしたもの)がスタックからポップされ、それぞれに対してデストラクタが呼び出されます。

于 2010-06-06T07:33:22.973 に答える
2

これにはいくつか問題があります。まず、なぜObject v4=v1なのですか。コピーコンストラクターを呼び出し、(b)の出力後にCopy-construct(1)を生成します。

=記号にもかかわらず、ここではコピーコンストラクターを呼び出しています。デフォルトのコンストラクターがないことを忘れないでください。新しいものを作成Objectし、の値で初期化しますv1。あなたがしたこと:

cout << "( b )" << endl;
Object v4(0);
v4 = v1;

...あなたが見るだろう...

( b )
Construct(0)
0 = 1

...あなたが期待していたと思います。

また、(c)の出力後、コピーコンストラクターが再び2回呼び出されますか?、この関数がどのように機能してそのオブジェクトを生成するのかわかりませんfunc(Object var){return var; }

varここでは、(参照[&]ではなく)値で渡します。これは、オブジェクトのコピーが作成されることを意味します(コピーコンストラクターへの1回の呼び出し)。次に、別のオブジェクトを(参照ではなく)返すため、別のコピーを作成する必要があります(コピーコンストラクターへの2回目の呼び出し)。

その直後に、(d)が出力される前にDestruct(1)が2回呼び出されます。

コピーコンストラクターで作成したオブジェクトは?彼らは範囲外になり、彼らのデストラクタが呼ばれました。

あなたがdelete v5そのデストラクタが呼び出されたとき。

次に、main関数の終わりに到達し、スタック上に作成した3つのインスタンスObject(、、v1)が存続期間の終わりに到達し、スタックが巻き戻されると破棄されます。v2v4

コンストラクタ呼び出しとまったく同じ数のデストラクタ呼び出しがあることにすでに気付いているでしょう。

于 2010-06-06T07:21:27.280 に答える
1

最初の質問は、のObject v4 = v1;構文糖衣ですObject v4(v1);。これは、より明らかにコピーコンストラクターを呼び出します。

2つ目はもう少し複雑です。変数を値で関数に渡すときは、それらをコピーする必要があります。つまり、コピーコンストラクターを呼び出します。オブジェクトのコピーは、関数が戻ると関数に渡されたコピーが存在しなくなるため、呼び出し元がアクセスできる場所のスタックにも配置する必要があります。これらの2つのコピーが作成された後、パラメーターはスタックからポップされるときに破棄され、戻り値はその値が使用されていないために破棄されます。それらはのコピーであるため、同じIDを持っていますv1

于 2010-06-06T07:08:18.497 に答える