この構文が正当であるためには、クラスに有効なコピーまたは移動コンストラクターが必要です。
C x = factory();
C y( factory() );
C z{ factory() };
C++03 では、コンパイラがコピー コンストラクターに触れるのを防ぐために、コピー省略に頼ることがかなり一般的でした。定義が存在するかどうかに関係なく、すべてのクラスには有効なコピー コンストラクターシグネチャがあります。
C++11 では、コピー不可能な型は を定義する必要C( C const & ) = delete;
があり、関数への参照は使用に関係なく無効になります (移動不可能な場合も同様)。(C++11 §8.4.3/2)。たとえば、GCC は、そのようなオブジェクトを値で返そうとすると文句を言います。コピーの省略は役に立ちません。
幸いなことに、抜け穴に頼るのではなく、意図を表現するための新しい構文もあります。このfactory
関数は波括弧初期化リストを返して、結果の一時的なインプレースを構築できます。
C factory() {
return { arg1, 2, "arg3" }; // calls C::C( whatever ), no copy
}
編集:疑問がある場合、このreturn
ステートメントは次のように解析されます。
- 6.6.3/2: 「ブレース初期化リストを含む return ステートメントは、指定された初期化子リストからのコピー リスト初期化 (8.5.4) によって、関数から返されるオブジェクトまたは参照を初期化します。」
- 8.5.4/1: 「コピー初期化コンテキストでのリスト初期化は、コピーリスト初期化と呼ばれます。」¶3: 「T がクラス型の場合、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され、オーバーロードの解決を通じて最適なコンストラクターが選択されます (13.3、13.3.1.7)。」
copy-list-initializationという名前に惑わされないでください。8.5:
13: 初期化の形式 (かっこまたは を使用
=
) は一般に重要ではありませんが、初期化子または初期化されるエンティティがクラス型を持つ場合は問題になります。下記参照。初期化されるエンティティにクラス型がない場合、括弧で囲まれた初期化子の式リストは単一の式になります。14:
T x = a;
引数の受け渡し、関数の戻り、例外のスロー (15.1)、例外の処理 (15.3)、および集合メンバーの初期化 (8.5.1) と同様にフォームで発生する初期化は、コピー初期化と呼ばれます。
copy-initialization とその代替であるdirect-initializationの両方は、初期化子が波括弧初期化リストである場合、常に list-initialization に従います。を追加しても意味的な効果はありません=
。これが、リスト初期化が非公式に均一初期化と呼ばれる理由の 1 つです。
違いがあります。直接初期化は、コピー初期化とは異なり、明示的なコンストラクターを呼び出す場合があります。コピー初期化は、変換時に一時オブジェクトを初期化し、それをコピーしてオブジェクトを初期化します。
ステートメントのcopy-list-initializationのreturn { list }
指定は、まったく同等の構文を betemp T = { list };
に指定するだけです。ここで、=
copy-initialization を示します。コピー コンストラクターが呼び出されることをすぐに意味するわけではありません。
-- 編集を終了します。
次に、関数の結果を右辺値参照に受け取って、一時的なものをローカルにコピーしないようにすることができます。
C && x = factory(); // applies to other initialization syntax
問題は、コピー不可、移動不可の型を返すファクトリ関数から非静的メンバーを初期化する方法です。参照メンバーは一時の有効期間を延長しないため、参照のトリックは機能しません。
集約初期化は考慮していないことに注意してください。これは、コンストラクターの定義に関するものです。