0

私の理解は間違っています。移動のポイントは、T または T& オーバーロードの代わりに T&& を強制することだと思いました。サインは

template typename remove_reference::type&& move (T&& arg) noexcept;

また、T&& は、参照が範囲外であることを意味することを除いて、T& と同じものだと思いました。私の理解では、画像のコードは安全なはずです。

rv.append は、新しいコピーを作成するか (範囲外になります)、範囲外になる rv を再利用します。移動があるため、実装がコピーを作成すると思いました。次に、再度追加してから移動します。それが戻ったとき、一時への参照であるため、一時がどこから来たのかがわからず、スタックにコピーしてその寿命を延期する必要があると思いました。

しかし、私は間違っていて、修正は画像とともにそこに書かれています。なぜそのように機能しないのですか?私が思ったように T&& は参照渡しですか?Rvalue 参照について他に知っておくべきことはありますか?

std::unique_ptr<T> make_unique1(U&& u)また、この例で2つの異なる関数を呼び出す方法もわかりません

ここに画像の説明を入力

4

3 に答える 3

4

rv.append は、新しいコピーを作成するか (範囲外になります)、範囲外になる rv を再利用します。

いいえ、それrv自体が変更されます。コピーはありません。を変更するメンバー関数呼び出しですrv

移動があるため、実装がコピーを作成すると思いました。

いいえ、rv.append()が呼び出されたとき、後で結果に対して発生する他の呼び出しの影響を受けず、std::string::append(const char*)on を呼び出すだけrvです。

次に、再度追加してから移動します。それが戻ったとき、一時への参照であるため、一時がどこから来たのかがわからず、スタックにコピーしてその寿命を延期する必要があると思いました。

いいえ、std::moveにキャストrvするだけstd::string&&です。スタックに何かをコピーする魔法はありません。戻り値は、 にバインドされた右辺値参照rvです。これは、 によって返される一時にバインドされた右辺値参照meow()です。次に、関数の外側で aconst std::string&が同じ一時にバインドされ、セミコロンで一時が範囲外にrなり、ダングリング参照として残ります。

于 2013-09-09T00:07:22.650 に答える
1

右辺値参照には名前があるため、それ自体が左辺値です。(名前でオブジェクトを参照できる場合、移動後の状態はほとんど未定義であるため、暗黙的に移動することは潜在的に安全ではないという考えです。)

string&& join(string&& rv, const char* ptr) {
    // rv is an lvalue here
    rv.append(", "); // modifying rv
    rv.append(ptr);  // modifying again
    return move(rv); // move required because rv is an lvalue
}

これは、渡された最初の引数への右辺値参照を返します。戻り値の型は参照であり、その参照の型は式の型と一致するため、rvからの戻り値へのコピーはありません。joinmove(rv)

の戻り値の型はjoinxvalue で、glvalue と右辺値です。したがって、const lvalue ref に直接バインドされますr(コピーは含まれません)。

一時的に返された frommeow()は、 full-expression の終わりまで続きますconst string& r = join(meow(), "purr");。有効期間が延長されないため、破棄されrてダングリング リファレンスになります。

于 2013-09-09T00:07:24.260 に答える
1

あなたが言うように、T&&は と同じようT&に参照であるため、ローカル変数への右辺値参照を返すことは、ローカル変数への通常の参照を返すことと同じです。どちらの場合も、ローカル変数 (この場合は一時変数) は、関数が終了し、無効な参照が取得されます。関数の戻り値への一時的なバインドの有効期間は、関数が終了するまでしか延長されないため、有効期間の延長は役に立ちません。

戻りstring値は、で作成したローカル/一時変数から (新しいオブジェクトとして) 移動構築されるため、値を返すとこれが修正されますmove(rv.append(", ").append(ptr))。そうすれば、一時オブジェクトが破棄されても、返されたオブジェクトは影響を受けません。

もう 1 つのコメントとして、結合関数はrv、右辺値参照 (string rvの代わりにstring&& rv) ではなく、値によってパラメーターを受け取る必要があります。移動コンストラクターが非常に高価でない限り (そうであってはなりません)、パフォーマンスは同じになり、一時的な値で関数を呼び出すこともできます。ムーブ コンストラクター以外で (またはテンプレート関数で) 右辺値参照として変数を宣言したい場合はほとんど考えられませんが、それは実際にはユニバーサル参照です)。

于 2013-09-09T00:07:39.950 に答える