名前空間
変種

コピー省略

提供: cppreference.com
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

コピーおよびムーブ (C++11以上)コンストラクタを省略し、ゼロコピーの値渡しセマンティクスを実現します。

説明

必須のコピー/ムーブ省略

以下の状況において、コンパイラは、たとえコピー/ムーブコンストラクタおよびデストラクタが観察可能な副作用を持っていたとしても、クラスオブジェクトのコピーおよびムーブ構築を省略することが要求されます。 オブジェクトは、それらのコピー/ムーブ先の記憶域に、直接構築されます。 コピー/ムーブコンストラクタは存在する必要もアクセス可能である必要もありません。

  • return 文において、被演算子が関数の戻り値の型と同じクラス型 (cv 修飾は無視します) の prvalue のとき。
T f() {
    return T();
}

f(); // T のデフォルトコンストラクタが一度だけ呼ばれます。
戻り値の型のデストラクタは、たとえ破棄される T のオブジェクトがなくても、 return 文の地点からアクセス可能でなければならず、削除されていてはなりません。
  • オブジェクトの初期化において、初期化子式が変数の型と同じクラス型 (cv 修飾は無視します) の prvalue のとき。
T x = T(T(f())); // x を初期化するために T のデフォルトコンストラクタが一度だけ呼ばれます。
これは初期化するオブジェクトが潜在的にオーバーラップする部分オブジェクトでないと判明しているときにのみ適用できます。
struct C { /* ... */ };
C f();
struct D;
D g();
struct D : C {
    D() : C(f()) { }    // 基底クラス部分オブジェクトを初期化するときは省略は行われません。
    D(int) : D(g()) { } // 初期化中の D オブジェクトが何らかの別のクラスの
                        // 基底クラス部分オブジェクトかもしれないため省略は行われません。
};

ノート: 上記のルールは最適化を規定しているのではありません。 C++17 コア言語の prvalue および一時オブジェクトの仕様は C++ の以前の版のそれとは根本的に異なります。 コピー/ムーブ元の一時オブジェクトはもはや存在しません。 C++17 の仕組みを説明する別の方法は「具体化されない値渡し」です。 prvalue は一時オブジェクトを一度も具体化することなく返され、使用されます。

(C++17以上)

必須でないコピー/ムーブ省略

以下の状況において、コンパイラは、たとえコピー/ムーブ (C++11以上)コンストラクタおよびデストラクタが観察可能な副作用を持っていたとしても、クラスオブジェクトのコピーおよびムーブ (C++11以上)構築を省略することが許されますが、要求はされません。 オブジェクトは、それらのコピー/ムーブ先の記憶域に、直接構築されます。 これは最適化です。 コピー/ムーブ (C++11以上)コンストラクタは、たとえ呼ばれないときでも、 (最適化がまったく行われなかった場合のように) 存在し、アクセス可能でなければなりません。 そうでなければ、プログラムは ill-formed です。

  • return 文において、被演算子が自動記憶域期間を持つ非 volatile オブジェクトの名前であり、それが関数の引数または catch 節の引数でなく、関数の戻り値の型と同じクラス型 (cv 修飾は無視します) であるとき。 コピー省略のこの変種は NRVO (named return value optimization; 名前付き戻り値の最適化) と言います。
  • オブジェクトの初期化において、ソースオブジェクトが名前のない一時オブジェクトであり、ターゲットオブジェクトと同じクラス型 (cv 修飾は無視します) のとき。 名前のない一時オブジェクトが return 文の被演算子のとき、コピー省略のこの変種は RVO (return value optimization; 戻り値の最適化) と言います。
(C++17未満)

戻り値の最適化は必須であり、もはやコピー省略とみなされません。 上を参照してください。

(C++17以上)
  • throw 式において、被演算子が自動記憶域期間を持つ非 volatile オブジェクトの名前であり、それが関数の引数または catch 節の引数でなく、そのスコープが最も内側の try ブロックを超えて延長されない (try ブロックがある場合) とき。
  • catch 節において、引数が投げられた例外と同じ型 (cv 修飾は無視します) のとき、例外オブジェクトのコピーは省略され、 catch 節の本体は、参照でキャッチしたかのように、その例外オブジェクトを直接アクセスします。 そのようなコピー省略が、 catch 節の引数のコピーコンストラクタおよびデストラクタをスキップする以外の何らかの理由でプログラムの観察可能な動作を変えるであろう場合は、これは無効化されます (例えば、 catch 節の引数が変更され、その例外オブジェクトが throw で投げ直される場合)。
(C++11以上)
  • コルーチンにおいて、引数のコルーチン状態へのコピー/ムーブは、それが引数のコンストラクタおよびデストラクタの呼び出しを省略すること以外にプログラムの動作を変更しなければ、省略されることがあります。 これは、引数が中断点より後に参照されることがない場合、またはコルーチン状態全体がそもそもヒープ確保されないときに、発生します。
(C++20以上)

コピー省略が発生したとき、処理系は省略されたコピー/ムーブ (C++11以上)操作のソースとターゲットを単に同じオブジェクトを参照する2つの異なる方法として扱い、そのオブジェクトの破棄は最適化がなかった場合に2つのオブジェクトが破棄されたであろうときに発生します (ただし、選択されたコンストラクタの引数がオブジェクト型への右辺値参照の場合は、破棄はターゲットが破棄されたであろうときに発生します) (C++17以上)

複数のコピーを省略するために複数のコピー省略が連鎖することがあります。