4
Class Cents(){  
 int m_val;  
 public:  
  Cents(int x=0){ cout<<"Constructor";}
  Cents(const Cents& src){ cout<<"Copy constructor"}
  Cents Add(int val){m_val=val; return *this}  // --->(1)
 }  

Cents object obj私が持っていて電話していると仮定しますobj.Add()

これで、出力は次のようになります

コンストラクタ
コピーコンストラクタ

したがって、私の仮定は、(1) を返すことで、オブジェクト値を新しい一時的な Cents オブジェクトに*thisコピーしていることです。*thisそのため、コピー コンストラクターが呼び出されます。

行(1)を次のように置き換えると

Cents Add(int val){ Cents temp;return temp;}  // --->(2)

唯一の出力は

コンストラクタ

コピーコンストラクターが呼び出されないのはなぜですか? 行(1)についての私の仮定は間違っていますか?

4

2 に答える 2

11

これはcopy elisionとして知られる最適化であり、頭字語が好きな人は "(N)RVO" ("(named) return valueoptimisation") と呼ぶこともあります。

特定の状況では、オブジェクトがある場所で (概念的に) 作成され、別の場所にコピーまたは移動されてから破棄される場合、プログラムは代わりに最終的な場所にオブジェクトを作成することができます。あなたの例のように、省略されたコンストラクターやデストラクタに副作用がある場合でも、この最適化は許可されます。

関数から一時変数またはローカル変数を返すことは、これらの状況の 1 つです。関数のスタック フレームに作成tempしてから呼び出し元にコピーする代わりに、プログラムは呼び出し元のフレームに直接作成することができます。

を返すと、関数の有効期間を超えている*thisため、コピーを省略できません。*this呼び出し元の観点からは、2 つのオブジェクトがあるため、プログラムは実際にコピーを作成する必要があります。

Cents original;
Cents copy = original.Add(42);

// "copy" and "original" both exist: the object must have been copied.

この最適化によって省略できる操作の詳細については、C++11 標準、12.8/31 を参照してください。

于 2013-08-15T12:36:40.223 に答える
3

これは、ほとんどのコンパイラが戻り値の最適化(別名 RVO) を実行してコピーを節約するために発生します。

于 2013-08-15T12:33:59.293 に答える