コピーの省略

C++プログラミングにおけるコピーの省略（コピーのしょうりゃく）とは、不必要なオブジェクトのコピーを除去するコンパイラ最適化技術のことである。C++言語標準は基本的に、出来上がったプログラムの表面上の動作が言語標準が義務付けた通りであれば、実装はどのような最適化を施しても良いとしている。（as-ifルール）

しかし、プログラムの動作が変更され得るにもかかわらず、それでもコピーが省略されうる状況を言語標準は幾つか挙げている。その中で最も有名なのが戻り値最適化であり、もう一つは、クラス型の一時オブジェクトが、同じ型のオブジェクトへとコピーされるときの最適化である。これも広く実装されており、C++言語標準で挙げられている。ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ ﾂｧ12.8 Copying class objects [class.copy] para. 15 結果的に、コピー初期化と直接初期化の間にパフォーマンス上の違いはないが、セマンティクス上ではそうではなく、コピー初期化にはアクセス可能なコピーコンストラクタが未だに必要である。 なお、参照に束縛されている一時オブジェクトは最適化されない。例:

#include <iostream>
int n = 0;
struct C {
  explicit C(int) {}
  C(const C&) { ++n; } // 目に見える副作用を持つコピーコンストラクタ
};                     // 静的な記憶時間を持つオブジェクトを書き換える

int main() {
  C c1(42); // 直接初期化。 C::C(42) を呼ぶ
  C c2 = C(42); // コピー初期化。 C::C( C(42) ) を呼ぶ

  std::cout << n << std::endl; // コピーが省略されたなら 0 、そうでなければ 1 を出力する
  return 0;
}

言語標準によると、例外として投げられるオブジェクトにも、同じような最適化が適用される。ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ ﾂｧ15.1 Throwing an exception [except.throw] para. 5ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ ﾂｧ15.3 Handling an exception [except.handle] para. 17 しかし、投げられたオブジェクトから例外オブジェクトへのコピー、そして例外オブジェクトから例外宣言のcatch節へのコピーのどちらも、最適化されるかもしれないし、されないかもしれない。これは、一時オブジェクトでも、名前付きオブジェクトでも同様である。 例:

#include <iostream>

struct C {
  C() {}
  C(const C&) { std::cout << "Hello World!\n"; }
};

void f() {
  C c;
  throw c; // 名前付きオブジェクト c を例外オブジェクトにコピー。
}          // このコピーが省略されるかどうかは不確かである。

int main() {
  try {
    f();
  }
  catch(C c) {  // 例外オブジェクトを例外宣言内の一時領域にコピー。
  }             // このコピーも省略されるかどうかは不確かである。
}

言語標準に準拠したコンパイラは、上記のコードから"Hello World!"と二度出力するプログラムを生成しなければならなかった。C++11では、名前付きオブジェクトの例外オブジェクトへのコピーと、例外ハンドラで宣言されたオブジェクトへのコピーを省略することを本質的に許したことで、その問題は対処された。

GCCはオプションを提供して、コピーの省略を無効化できるようにしている。このオプションは戻り値最適化の効果を発見（あるいは見逃し！）するのに有用である。平時にこの重要な最適化を無効化することは推奨しない。
 脚注 

Category:コンパイラ最適化
Category:C++