これらのコードフラグメントは、ほとんど同等です。
Foo&& rf = Foo();
は、参照の一時的な存続期間を参照の一時的なものにバインドしています。 Foo
は、が有効範囲外になった場合にのみ破棄されます。あなたはどちらを取得する動作と同じです。後者の例f
にデフォルトの初期化であるが、前者の例ではが値に初期化されることを除いて
Foo f;
。いくつかのタイプについては、2つは同等です。他の人にとっては、そうではありません。代わりにFoo f{}
と書かれていた場合、この違いはなくなります。がgive_a_foo_rv()
の戻り型と同じ型を持っていないので、
Foo give_a_foo_rv() {
Foo&& rf = Foo();
return rf;
}
Foo give_a_foo() {
Foo f{};
return f;
}
RVOは、実施例1で行うことを許可されていない。
一つ残りの違いは、エリジオンをコピーすることに関する。また、それは自動記憶域期間を持っていないので、それはオブジェクトではないのでも、自動的に戻り値の型に移動されませんので、それは余分なコピーです:
Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo(); // no move or copy
それを明確に思えますコピーはありません。
Foo
が実際に何を動かすかによって完全に決まります。 Foo
がどのように見える場合:
struct Foo {
Foo() = default;
Foo(Foo const&) = default;
Foo& operator=(Foo const&) = default;
// some members
};
その後、Foo
を移動させることは、まだコピーを行います。
はい、それは完全に大丈夫ですstd::move(f)
2番目の例です。そこからT
〜move
への参照値タイプのオブジェクトは必要ありません。それは、移動の有用性を厳しく制限します。
あなたの最初の部分はコンパイルすべきではありません。第二の部分はあなたが望むものを正確に行います。 std :: moveはcnをrvalueにして、それをm_fooに移動します(移動演算子は削除されないなどと仮定します)。 – Hayt
@Hayt、それはなぜコンパイルしてはいけないのですか?私が理解しているように、一時的な値をref値に代入することは、一時的なものの寿命を延ばします(通常の参照であれば、それはコンパイルされません) –
ああ。その方法をコーディングしている人は見たことがありません(本当に必要なことではありません)。しかし、依然として、右値でないオブジェクトを右辺値にするために移動が行われます。 – Hayt