6
#include <iostream>
using namespace std;

class A
{
    int x;

public:
    A(int c) : x(c) {}
    A(const A& a) { x = a.x; cout << "copy constructor called" << endl;}
};

class B
{
    A a;

public:
    B(int c) : a(c) {}
    B(const B& b) : a(b.a) { }
    A get_A() { return a;}
};

int main()
{
    B b(10);
    A a1 = b.get_A();

}

上記のコードでは、最初に b.get_A() がコピー コンストラクター (1) を呼び出す一時オブジェクトを作成し、次にその参照を a1 にコピーするため、「コピー コンストラクターが呼び出されました」というメッセージが 2 回表示されると予想していました。 s copy constructor (2) 。したがって、2 つのメッセージが表示されます。

ただし、コードは実際には単一の「コピー コンストラクターが呼び出されました」というメッセージを生成します。なんで?

4

2 に答える 2

10

C++ 標準では、特定の状況でコピー コンストラクターを省略できます。通常、これはオブジェクトが一時変数からコピー構築されるかどうかを意味します。その場で施工可能です。

この場合get_A();、一時的にコピーを返しました。次に、a1その一時変数に代入します。コンパイラは、余分なコピーを省略a1し、戻り値の代わりに構築することができますget_A()

この最適化は、コピー コンストラクターに副作用がある場合でも発生する可能性があります。

コピー省略は、観察可能な副作用を変更できる最適化の唯一の許可された形式です。一部のコンパイラは、許可されているすべての状況でコピー省略を実行しないため、コピー/移動コンストラクターおよびデストラクターの副作用に依存するプログラムは移植できません。

于 2013-05-26T07:23:31.353 に答える
3

C++11 では、コードは移動コンストラクターを呼び出して、オブジェクトをコピーするのではなくオブジェクトを移動する場合があります。または、C++03 と C++11 の両方のコンパイラーの最適化では、NRVO の形式でコピー省略を適用してコピーを削除する場合があります。

後者 ( copy elision ) はコンパイラの機能に依存し、保証されていないことに注意してください。一方、前者 ( Move Semantics ) は C++11 で保証されています。

于 2013-05-26T07:23:52.347 に答える