C 11 Move コンストラクターは呼び出されず、デフォルト コンストラクターが優先されます
C でクラスを操作する場合、移動コンストラクターは次の目的で使用されることが期待されます。効率的なリソース転送。ただし、場合によっては、代わりにデフォルトのコンストラクターが予期せず選択されることがあります。
問題ステートメント
次のクラスを考えてみましょう:
<code class="cpp">class X { public: explicit X(char* c) { cout << "ctor" << endl; init(c); } X(X& lv) { cout << "copy" << endl; init(lv.c_); } X(X&& rv) { cout << "move" << endl; c_ = rv.c_; rv.c_ = nullptr; } const char* c() { return c_; } private: void init(char* c) { c_ = new char[strlen(c) + 1]; strcpy(c_, c); } char* c_; };</code>
With使用例:
<code class="cpp">X x("test"); cout << x.c() << endl; X y(x); cout << y.c() << endl; X z(X("test")); cout << z.c() << endl;</code>
期待される出力は次のとおりです:
ctor test copy test ctor move test
ただし、最後の行は予期せず「move」ではなく「ctor」を出力します。
説明
C 11 標準によれば、特定の状況では移動コンストラクターを呼び出す必要があります。この場合、X("test") で z を構築するときに移動が発生する必要があります。ただし、代わりにデフォルトのコンストラクターが呼び出されます。
この動作は、コピーまたは移動操作を実行せずに、コンパイラーがターゲットに一時オブジェクトを直接構築できるようにする最適化手法であるコピー省略によるものです。この最適化は、コピー/移動操作が不要で省略できるとコンパイラーが判断した場合に適用されます。
指定されたシナリオでは、コンパイラーは一時的な X("test") をコピー省略の候補と見なします。同じ式内で自動的に作成および破棄されるためです。その結果、移動操作が省略され、一時データを使用して z が直接構築され、その結果、デフォルトのコンストラクターが呼び出されます。
結論
コピーの省略により、予期せぬ結果が生じる可能性があります。これは、移動コンストラクターが予期される状況で呼び出されなくなる可能性があるためです。コンパイラは、最適化ヒューリスティックに基づいてコピー省略を適用する場合がありますが、これはコンパイラや最適化設定によって異なります。コピーの省略と、それがプログラムの動作に与える潜在的な影響を認識することが重要です。
以上がコピー省略が有効になっている場合、C 11 で Move コンストラクターが呼び出されないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。