2015-11-20 6 views
5

Nehmen wir an, ich habe struct Foo mit Bewegung constructor und operator=(Foo&&), und ich benutzte es als Daten Mitglied:C++ Std :: Umzug ist hier schlecht?

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

Bei (2) ich nicht wirklich std::move brauchen, aber was ist, wenn ich es benutzt hier macht dies etwas schlechtes, wie verhindern Optimierung?

Ich lese diese: Why does std::move prevent RVO?

und finden Sie heraus, dass return foo;-return std::move(foo); Ursache Sperrung des RVO ändern, aber was (2) es eine ähnliche Situation verursacht? Und wenn ja, warum?

+7

Kopieren Elision würde in diesem Fall sowieso nicht gelten, weil Sie 'foo.operator =' aufrufen. Es wäre relevant, wenn Sie 'Foo foo = std :: move (f());' haben, was die Initialisierung ist. –

+1

@ M.M Aber "clang 3.7" warnen darüber, so frage ich mich, ist es Bug in der Warnung Generation, oder ich habe etwas verpasst – user1244932

+1

Es kann schlecht sein, aus Gründen, die nicht Leistung Gründen zu. In Ihrem Fall für # 2, Sie kümmern sich std :: move (f()) auf etwas, das bereits ein rhr ist, so ist die Bewegung verschwendet Zeichen. Meine Faustregel ist, dass Sie std :: move vermeiden sollten, es sei denn Sie müssen, und Sie müssen nur, wenn Sie Eigentumsrechte in einer nicht-trivialen Weise übertragen. – IdeaHat

Antwort

5

Es ist redundant und verwirrend. Nur weil ich std::add_pointer_t<void> anstelle von void* schreiben kann, oder std::add_lvalue_reference_t<Foo> (oder Foo bitand) anstelle von Foo&, bedeutet das nicht, dass ich sollte.

Es kommt auch in anderen Zusammenhängen:

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

und so, wenn Foo ist etwas, das über laufen werden kann,

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

Und in Ihrem Beispiel, wenn der Zuweisungsoperator implementiert, wie copy-and-swap (operator=(Foo)), dann foo = std::move(f()) erzwingt eine nicht elimierbare Bewegung, während foo = f() kann die Bewegung von f() Rückgabewert an das Argument operator=.

+0

In diesem ersten Beispiel scheint "b" nicht zu baumeln, wenn es von 'VS2013' kompiliert wird. (Habe noch nicht mit einem anderen Compiler getestet). Könnten Sie bitte ein wenig mehr Informationen dazu geben? –

+0

@DeanSeo Weder [clang] (http://coliru.stacked-crooked.com/a/607b0d720af30b9e) noch [gcc] (http://coliru.stacked-crooked.com/a/698d5c5271c8f1c8) verlängern die Lebensdauer von das vorläufige. Ersteres wird sogar einige nette Leistungswarnungen ausgeben. –

+0

@ MatthäusBrandl Ich glaube nicht, dass 'std :: move (f())' das temporäre ist, aber es wird wahrscheinlich sehr bald als xvalue verschoben werden. Also ist es noch nicht bewegt ...? (bedeutet nicht baumeln). Ich habe dies vor langer Zeit gepostet, vielleicht brauche ich etwas Zeit, um aufzuholen. –