2015-11-20 99 views
5

讓我們假設我有struct Foo與移動constructoroperator=(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, 但如果我用在這裏,這是否會造成不好的結果, 就像阻止優化一樣?

我這樣說的:Why does std::move prevent RVO?

,並找出改變RVOreturn foo;return std::move(foo);原因禁用,但對於(2)不會造成類似的情況?如果是這樣,爲什麼?

+7

無論如何,複製elision不適用於這種情況,因爲您正在調用'foo.operator ='。如果你有'Foo foo = std :: move(f());'這是初始化。 –

+1

@ M.M但是'clang 3.7'對此有所警告,所以我想知道,它是警告生成中的缺陷,還是我錯過了一些東西 – user1244932

+1

由於性能原因,這可能是不好的原因。在你的情況#2,你關心調用std :: move(f())已經是rhr的東西,所以移動是浪費的字符。我的經驗法則是,除非必須,否則您應該避免std :: move,並且您只需要在以非平凡方式轉讓所有權時。 – IdeaHat

回答

5

這是多餘的和令人困惑的。僅僅因爲我可以寫std::add_pointer_t<void>而不是void*std::add_lvalue_reference_t<Foo>(或Foo bitand)而不是Foo&,並不代表我應該。

這也很重要在其他情況下:

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移動。所以它還沒有移動...? (意思是不搖晃)。我很久以前發佈了這個,所以也許我需要一些時間趕上。 –