2016-09-07 9 views
11

オブジェクトを作成するときにr値参照を使用する利点はありますか?それ以外の場合は通常のローカル変数になりますか?最初のコードスニペットでオブジェクト、ローカル変数とrvalue参照の作成

Foo&& cn = Foo(); 
cn.m_flag = 1; 
bar.m_foo = std::move(cn); 
//cn is not used again 

Foo cn; 
cn.m_flag = 1; 
bar.m_foo = std::move(cn); //Is it ok to move a non rvalue reference? 
//cn is not used again 

は、すべてのコピーがないことは明らかようだが、私は2番目にコンパイルがコピーを最適化するだろうと推測するだろうか?また、最初のスニペットに、物体が実際にメモリに記憶されている

(第二に、それは、囲み関数のスタックフレームに格納されていますか)?

+0

あなたの最初の部分はコンパイルすべきではありません。第二の部分はあなたが望むものを正確に行います。 std :: moveはcnをrvalueにして、それをm_fooに移動します(移動演算子は削除されないなどと仮定します)。 – Hayt

+0

@Hayt、それはなぜコンパイルしてはいけないのですか?私が理解しているように、一時的な値をref値に代入することは、一時的なものの寿命を延ばします(通常の参照であれば、それはコンパイルされません) –

+0

ああ。その方法をコーディングしている人は見たことがありません(本当に必要なことではありません)。しかし、依然として、右値でないオブジェクトを右辺値にするために移動が行われます。 – Hayt

答えて

8

これらのコードフラグメントは、ほとんど同等です。

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番目の例です。そこからTmoveへの参照値タイプのオブジェクトは必要ありません。それは、移動の有用性を厳しく制限します。

関連する問題