2

以下のコードから、クラス CA に対して次のものが呼び出されることを期待していました

  1. 関数によって返される一時オブジェクトを作成するコンストラクタfoo
  2. aメインの変数に渡す変数を作成するコピーコンストラクタ
  3. a関数によって返された値から変数を作成する別のコピー コンストラクター。

なぜそうではないのですか?私が持っている結果はちょうど

A

期待してたのに

ABB

したがって、コンストラクターのみが呼び出されます。コンパイラは舞台裏で何かを最適化していますか、それとも C++ の概念を見逃していますか?

class CA{
public:
   CA(){ std::cout << "A"; }
   CA( const CA& ){ std::cout << "B"; }
   CA& operator=(const CA& ){ std::cout << "C";return *this; }
};

CA foo(){
      return CA();
}

int main(){
 CA a = foo();    
}
4

2 に答える 2

8

コンパイラは舞台裏で何かを最適化していますか、それとも C++ の概念を見逃していましたか?

スポット!コピー省略といいます。Google で RVO と NRVO を調べてください。また、3 のルールを調べる必要があります。

コピー省略は、監視可能な動作に影響を与える、コンパイラが実行できる唯一の最適化です。そのため、重要なロジックをコピー コンストラクターに配置しないでください。

于 2012-07-14T16:45:59.703 に答える
0

C++ には、少なくとも 2 つの「種類」の最適化があります。

  • 最初の種類は、言語仕様によって明示的に導入された特定の最適化です。

  • 2 番目の種類は、コンパイラが "as-if" ルールの下で実行するワイルドで予測不可能な最適化です (つまり、プログラムの観察可能な動作が変更されない限り、コンパイラは絶対に何でも実行できます)。

(2 番目の種類の最適化のみが真の最適化であると言う人もいるかもしれません。)

ここに表示されるのは、第 1 種の最適化です。複数ステップのコピー操作を実行する場合、言語仕様では、コンパイラが中間の一時コピーを削除することを常に明示的に許可していました。

さらに、言語仕様の C++03 以降のバージョンでは、さらに一歩進んでいます。それらは、コンパイラが「名前付き戻り値の最適化」(NRVO) を実行することを明示的に許可しています。

どちらも、プログラム内のコピー操作の数を減らします。

C++ でのこのようなコピー削除の最適化は、プログラムの観察可能な動作を変更する場合でも許可されます。つまり、第 1 種の最適化は第 2 種の制限に違反することがあります。あなたの場合、コピー コンストラクターに I/O 操作を挿入しても、コンパイラーはそのコンストラクターの呼び出しを排除することが許可されています。

投稿したコードは NRVO を必要としません。優れた C++98 コンパイラは、観察した結果を生成できるはずです。そのような場合にコンパイラが NRVO を実行するかどうかを確認したい場合は、これを試してください。

CA foo(){
  Ca ca;
  return ca;
}
于 2012-07-14T16:52:46.060 に答える