Diese Codefragmente sind meistens gleichwertig. Dies ist:
bindet eine temporäre an eine Referenz, die die Lebensdauer des temporären auf die der Referenz verlängert Die Foo
wird nur zerstört, wenn rf
den Gültigkeitsbereich verlässt. Welches ist das gleiche Verhalten, das Sie mit bekommen:
Foo f;
mit der Ausnahme, dass im letzteren Beispiel f
ist default-initialisiert, aber in dem früheren Beispiel rf
ist Wert initialisiert. Bei einigen Typen sind die beiden gleichwertig. Für andere sind sie nicht. Wenn Sie stattdessen Foo f{}
geschrieben hätten, dann würde dieser Unterschied verschwinden.
Eine verbleibende Differenz betrifft elision kopieren:
Foo give_a_foo_rv() {
Foo&& rf = Foo();
return rf;
}
Foo give_a_foo() {
Foo f{};
return f;
}
RVO nicht im ersten Beispiel durchgeführt werden darf, weil rf
nicht den gleichen Typ wie der Rückgabetyp give_a_foo_rv()
haben. Darüber hinaus wird rf
nicht einmal automatisch in den Rückgabetyp verschoben werden, da es kein Objekt ist, so dass es keine automatische Speicherdauer hat, so ist das eine zusätzliche Kopie:
Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo(); // no move or copy
es scheint klar, dass es keine Kopien geben wird
Das hängt ganz davon ab, was ein Foo
tatsächlich bewegt. Wenn Foo
wie folgt aussieht:
struct Foo {
Foo() = default;
Foo(Foo const&) = default;
Foo& operator=(Foo const&) = default;
// some members
};
dann eine Foo
noch in Bewegung tut Kopieren.
Und ja, es ist vollkommen in Ordnung zu std::move(f)
im zweiten Beispiel. Sie brauchen kein Objekt vom Typ rvalue reference zu T
zu move
von ihm. Dies würde die Nützlichkeit des Bewegens stark einschränken.
Ihr erster Teil sollte nicht einmal kompilieren. Der zweite Teil macht genau das, was Sie wollen. std :: move macht cn zu einem rvalue und verschiebt es dann zu m_foo (vorausgesetzt, die move-Operatoren werden nicht gelöscht usw.). – Hayt
@Hayt, warum sollte es nicht kompilieren? Wie ich es verstehe, verlängert das Zuweisen eines temporären zu einem r Wert ref die Lebensdauer des temporären (wenn es eine normale Referenz wäre, dann würde es ja nicht kompilieren) –
Ah ok. habe nie jemanden gesehen, der so codiert hat (es ist nicht wirklich notwendig).Die Bewegung wird jedoch meistens dazu verwendet, ein Nicht-Rvalue-Objekt zu einem R-Wert zu machen. – Hayt