Eine const
lvalue-Referenz kann sich an alles binden. Eine rvalue-Referenz kann sich nur an nicht-const
rvalues binden.
non-const lvalue const lvalue non-const rvalue const rvalue
const T& yes yes yes yes
T&& no no yes no
Wie Sie sehen können, sind sie sehr unterschiedlich.
Zusätzlich, wenn ein Funktionsaufruf eine lvalue-Referenz zurückgibt, ist dieser Ausdruck eine lvalue, aber wenn ein Funktionsaufruf eine rvalue-Referenz auf ein Objekt zurückgibt, ist dieser Ausdruck ein xvalue.
Ein Funktionsaufruf ist eine lvalue, wenn der Ergebnistyp ein lvalue-Referenztyp oder eine rvalue-Referenz auf Funktionstyp ist, ein xvalue, wenn der Ergebnistyp ein rvalue-Referenz auf Objekttyp ist, und ein prvalue, wenn dies nicht der Fall ist.
Wenn Sie ein rvalue ändern möchten - genau das sind die Bewegungssemantiken. Betrachten Sie den folgenden Funktionsaufruf:
void func(std::string);
func(std::string("Hallo"));
Der Ausdruck std::string("Hallo")
ist eine rvalue, die ein temporäres Objekt erstellt. Beim Initialisieren des Parameters std::string
mit dieser rvalue wird der Konstruktor gewählt, der eine rvalue-Referenz akzeptiert - der Bewegungskonstruktor. Dieser Konstruktor stiehlt dann Dinge von der rvalue, was typischerweise viel schneller ist als eine vollständige Kopie. Wir können von ihm stehlen, weil wir wissen, dass es temporär ist.
Bezüglich des Rückgabetyps von const
lvalue-Referenzen oder rvalue-Referenzen:
-
Das Zurückgeben eines const
lvalue-Verweises wird am häufigsten verwendet, wenn Sie Zugriff auf das Lesen eines "internen" Objekts geben möchten (vielleicht ein Element einer Klasse), aber Personen nicht erlauben möchten, es zu ändern.
-
Das Zurückgeben einer rvalue-Referenz wird am häufigsten verwendet (sehr selten), wenn Sie möchten, dass der aufrufende Code von einem "internen" Objekt (vielleicht ein Element einer Klasse) verschoben werden kann. Anstatt also von einem temporären zurückgegebenen Objekt zu verschieben (wie bei der Rückgabe durch Wert), verschieben sie tatsächlich das interne Objekt.
Dies könnte auch mit einem nicht-const
lvalue-Verweis erreicht werden, aber dann müssten sie es explizit mit std::move
verschieben.
Es ist also sehr unwahrscheinlich, dass Sie eine rvalue-Referenz zurückgeben müssen.
Nicht dass std::forward
einen Rückgabetyp hat, der wie T&&
aussieht. Dies ist jedoch irreführend, da es je nach Typ von T
eine rvalue-Referenz sein kann oder nicht. Siehe universal references.