2015-11-20 8 views
5

はのは、私が移動constructoroperator=(Foo&&)struct Fooを持っているとしましょう、と私はデータメンバとしてそれを使用:場合C++ std :: moveはここで悪いですか?

Foo f() 
{ 
    Foo foo; 
    //code 
    return foo; 
} 
struct Boo { 
Foo foo; 
Boo() { 
    foo = f();//1 
    foo = std::move(f());//2 
} 
}; 

私はここでそれを使用した場合(2)私は実際にstd::move、 が、何を必要としません、これは何か悪くしますか? は最適化を妨げるのですか?

私はこの読み:(2)それは似たような状況を引き起こすんWhy does std::move prevent RVO?

をしてRVOreturn foo;return std::move(foo);に原因の無効化を変更することを見つけるが、何は?もしそうなら、なぜですか?

+7

この場合、 'foo.operator ='を呼び出すので、コピーelisionは適用されません。 'Foo foo = std :: move(f());'が初期化されていれば関係します。 –

+1

@ M.Mしかし、 'clang 3.7'はこれについて警告しているので、警告生成のバグですか、何かが逃したのでしょうか? – user1244932

+1

パフォーマンス上の理由でもないことも悪いことがあります。 #2の場合、str :: move(f())をすでにrhrと呼んでいるので、移動は無駄になります。私の経験則では、あなたがする必要がない限り、あなたはstd :: moveを避けなければならないということです。そして、あなたは自明ではない方法で所有権を移譲しなければなりません。 – IdeaHat

答えて

5

冗長で混乱します。ただvoid*、またはFoo&の代わりにstd::add_lvalue_reference_t<Foo>(またはFoo bitand)の代わりにstd::add_pointer_t<void>と書くことができるので、私はすべきではありません。

それはまた別の文脈で重要:

auto&& a = f(); // OK, reference binding to a temporary extends its lifetime 
auto&& b = std::move(f()); // dangling 

ので、代入演算子は次のように実装されている場合Fooは、繰り返し処理することができるもの、

for(const auto& p : f()) {} // OK 
for(const auto& p : std::move(f())) {} // UB 

そして、あなたの例である場合コピー&スワップ(operator=(Foo))の場合、foo = std::move(f())は解除不能な移動を強制しますが、foo = f()f()の戻り値からoperator=の引き数への移動を取り除くことができます。

+0

最初の例では、 'VS2013'によってコンパイルされたとき、' b'はぶら下がっているように見えません。 (他のコンパイラでまだテストしていない)。それについてもう少し詳しくお聞かせください。 –

+0

@DeanSeo [clang](http://coliru.stacked-crooked.com/a/607b0d720af30b9e)や[gcc](http://coliru.stacked-crooked.com/a/698d5c5271c8f1c8)も、一時的な。前者は素晴らしいパフォーマンス警告を出します。 –

+0

@MatthäusBrandl私は 'std :: move(f())'は一時的だとは思っていませんが、すぐにxvalueとして移動されるでしょう。だからまだ動いていない...? (ぶら下がっていないことを意味する)。私はこれをずっと前に投稿していたので、追いつくのに時間が必要かもしれません。 –

関連する問題