ホームページ >バックエンド開発 >C++ >一時オブジェクトを使用して別のオブジェクトを初期化するときに、C 11 Move コンストラクターが呼び出されないのはなぜですか?

一時オブジェクトを使用して別のオブジェクトを初期化するときに、C 11 Move コンストラクターが呼び出されないのはなぜですか?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-11-05 05:06:021009ブラウズ

Why is the C  11 Move Constructor Not Called When a Temporary Object is Used to Initialize Another Object?

C 11 移動コンストラクターは呼び出されず、デフォルト コンストラクターが優先されます

説明:
C 11 で移動セマンティクスを使用する場合、次のことが可能です。デフォルトのコンストラクターが優先されて、移動コンストラクターが予期せずスキップされるシナリオが発生します。この記事では、この問題を調査し、根本的な理由を調べ、解決策を提供します。

問題:
メッセージを出力するコンストラクターを備えた次のクラス X を考えてみましょう:

<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>

以下に示すサンプル使用法では、3 つのオブジェクトを作成します:

<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>

ただし、z に対して呼び出される移動コンストラクターを示す予想される出力の代わりに、デフォルトのコンストラクターが代わりに使用されます。

標準への準拠:
C 11 標準 (§12.8.32) に従って、可能な限りコピー セマンティクスよりも移動セマンティクスを優先する必要があります。したがって、この場合、実際に z に対して move コンストラクターを呼び出す必要があります。

動作の説明:
観察された動作は、copy elision。 C 11 では、パフォーマンスを向上させるために、特定の状況でコンパイラがオブジェクトのコピー/移動を省略できるようになります。これらの状況の 1 つは、一時オブジェクトが同じ cv 非修飾型のオブジェクトにコピー/移動される場合です。

サンプル コードの最後の行で、X("test") は一時的な X を作成します。オブジェクトであり、ターゲット (z) と同じ cv 非修飾型を持ちます。したがって、コンパイラーは、コピー コンストラクターと移動コンストラクターを省略し、どちらのコンストラクターも呼び出すことなく、一時オブジェクトを z に直接構築することができます。

解決策:移動コンストラクターを強制的に次のようにします。呼び出されると、std::move() を使用して、移動が行われることを明示的に示すことができます:

<code class="cpp">X z( std::move(X("test")) );</code>
この変更により、期待される出力が生成され、移動コンストラクターの関与が確認されます。

以上が一時オブジェクトを使用して別のオブジェクトを初期化するときに、C 11 Move コンストラクターが呼び出されないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。