4

次のような関数があるとどうなるのだろうと思っています。

typedef std::unordered_map<std::string,std::string> stringmap;

stringmap merge (stringmap a,stringmap b) 
{
  stringmap temp(a); temp.insert(b.begin(),b.end()); return temp;
}

関数が戻るとどうなりますか?

「temp」は破棄される前に一時的な r-value にコピーされ (範囲外)、C++11 では NRVO 最適化される可能性があります (したがって、「temp」のコピーは戻り先スロットに直接書き込まれます)。

4

3 に答える 3

7

何もコピーしないでください。次の 2 つの可能性があります。

  • temp呼び出し元のスコープ内のオブジェクトに移動されます。また
  • 移動は省略さtempれ、呼び出し元のスコープ内のオブジェクトのエイリアスになります。これは「戻り値の最適化」として知られています。

2011 年より前 (具体的には移動セマンティクスなし) では、最初のケースでは移動ではなくコピーが必要でした。2 番目のケースは、11 と同様に C++98 でも許可されていました。

于 2013-04-03T16:52:44.370 に答える
5

NRVO は、tempそれ自体が戻り値の場所に構築されていることを意味します。RVO がなければ、はい、temp破棄される前に、スタック上のその場所から戻り値の場所にコピー/移動されます。

于 2013-04-03T16:50:26.990 に答える
4

これは通常、特別なルールがなくてもtemp、関数の戻り値へのコピーになります。ただし、標準には、これを改善することを目的とした 2 つの規則があります。1 つ目は、コピーが省略される可能性があることです (12.8/31):

クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cvunqualified 型を持つ不揮発性自動オブジェクト (関数または catch-clause パラメーター以外) の名前である場合、コピー/move 操作は、自動オブジェクトを関数の戻り値に直接構築することで省略できます

これは、戻り値の最適化 (RVO) の特殊なケースである名前付き戻り値の最適化 (NRVO) としてよく知られています

2 つ目は、この状況が上記のコピー省略の基準を満たしているため、最初に移動と見なされることです (12.8/32)。

コピー操作の省略の基準が満たされているか、ソース オブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値によって指定されているという事実を除いて満たされる場合、コピーのコンストラクターを選択するためのオーバーロードの解決は次のとおりです。オブジェクトが右辺値によって指定されたかのように最初に実行されます。

そのため、コンパイラは次の手順を試みます。

  • クラスに移動コンストラクターはありますか?
    • もしそうなら、それを移動するか、移動を省略します。
    • そうでない場合、クラスにはコピー コンストラクターがありますか?
      • もしそうなら、それを移動するか、コピーを削除してください。
      • そうでない場合、このオブジェクトをコピーまたは移動できません。

移動またはコピーが省略されている場合でも、これが機能するには、クラスに移動またはコピー コンストラクターが必要であることに注意してください。

于 2013-04-03T16:49:50.020 に答える