0

この記事に基づいて、http://www.drdobbs.com/cpp/when-is-it-safe-to-move-an-object-instea/240156579#disqus_thread

次のコードは移動コンストラクターを呼び出しません。

void func()
{
    Thing t;
    work_on(t);
    // never using t variable again ...
}

次のコードは、move コンストラクターを呼び出します。

work_on(Thing());

その理由は、最初のコード スニペットのためです。コンストラクターは、構築オブジェクトのアドレスを保存し、後でそれを使用する可能性があります。

私の質問は次のとおりです。しかし、2 番目のコード スニペットでは、C++ 標準に基づいて work_on が終了する前に一時オブジェクトがまだ生きているため、作成者は構築オブジェクトのアドレスを保存し、それを work_on 関数内で使用することもできます。同じ理由で、move コンストラクターも呼び出すべきではありません。これは意味がありませんか?

4

2 に答える 2

1
void func()
{
    Thing t;

    work_on(t);       // <--- POINT 1

    work_on(move(t)); // <--- POINT 2

    work_on(Thing()); // <--- POINT 3
}

tPOINT 1の式はlvalue.

move(t)POINT 2の表現はxvalue.

POINT 3の式Thing()は aprvalueです。

式のこの値カテゴリに基づいて、オーバーロードされたセットから最適な実行可能な関数が選択されます。

使用可能な 2 つの機能が次のとおりであるとします。

work_on(const Thing&); // lvalue reference version
work_on(Thing&&);      // rvalue reference version

Anlvalueは左辺値参照バージョンを選択し、右辺値参照バージョンにバインドすることはありません。

xvalueor prvalue(まとめて と呼ばれる)rvaluesはどちらかに有効にバインドされますが、使用可能な場合はより適切な一致として右辺値参照バージョンを選択します。

の 2 つのバージョンの実装内ではwork_on、パラメータはほとんど同じです。これの目的は、右辺値参照バージョンが引数を変更または移動するものであると想定できるようにすることです。そのため、その引数で移動コンストラクターを呼び出すことができますが、左辺値参照バージョンはそうすべきではありません。

したがって、パラメーターを追加する必要があるvector<Thing> Vものがあるとします。work_on

void work_on(Thing&& t)
{
    V.push_back(move(t));
}

void work_on(const Thing& t)
{
    V.push_back(t);
}

std::vector::push_backと同様の方法でオーバーロードされ、work_on同様のオーバーロード解決が行われます。の 2 つの異なる実装内でpush_back、右辺値参照バージョンは move コンストラクターを呼び出して値をその配列にプッシュし、場合によっては を破棄しtます。左辺値参照バージョンはコピー コンストラクターを呼び出し、tそのまま残します。

この言語メカニズムの主な目的は、変数 (lvalues)、意図的にマークされた期限切れの値 (xvalues)、および一時変数 (prvalues) を追跡することです。これにより、それらのリソースをいつ安全に再利用 (移動) できるか、いつコピーできるかがわかります。彼ら。

于 2013-06-19T09:23:30.533 に答える