rvalue reference
-
Hi,
eine kurze Frage: Ist eine rvalue reference ein lvalue?
Danke im Voraus.
-
http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues und http://i.stack.imgur.com/YKlod.png für den Graph.
Ein rvalue kann nie ein lvalue sein, wohl aber ein glvalue. Welches meintest du
-
Ist eine rvalue reference ein lvalue?
Ja, wenn sie einen Namen hat. Das ist eine wichtige Regel.
§5/6 schrieb:
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.
Ein rvalue kann nie ein lvalue sein, wohl aber ein glvalue.
Das hat mit der Frage im OP nichts zu tun.
-
prval schrieb:
Ein rvalue kann nie ein lvalue sein, wohl aber ein glvalue. Welches meintest du
Ja, das ist klar. Ich mein aber ja auch keinen rvalue, sondern eine rvalue-reference. Also ich hab das so verstanden: Ich kann einen rvalue an eine rvalue-reference. Damit hat der rvalue sozusagen einen Namen bekommen. Was einen Namen hat ist ein lvalue. Also ist eine rvalue-reference ein lvalue.
Hab ich das so richtig verstanden?
-
out schrieb:
Also ich hab das so verstanden: Ich kann einen rvalue an eine rvalue-reference
binden.
edit: Wort vergessen.
-
Ich kann einen rvalue an eine rvalue-reference. Damit hat der rvalue sozusagen einen Namen bekommen. Was einen Namen hat ist ein lvalue. Also ist eine rvalue-reference ein lvalue.
Alles richtig. Der letzte Satz ist nur zu pauschal (und dazu grammatikalisch falsch, das kannst du so nicht sagen, nur Ausdrücke können lvalues sein).
Ist dir bewusst, dass eine rvalue reference (genau wie eine const lvalue reference) die Lebenszeit eines rvalues verlängert?
-
Sone schrieb:
Ist dir bewusst, dass eine rvalue reference (genau wie eine const lvalue reference) die Lebenszeit eines prvalues verlängert?
Joa. Das dürfte bei Funktionsüberladung lustig werden.
-
Übrigens falsch ausgedrückt. Die verlängert die Lebenszeit einer Temporary.
Wenn du eine rvalue reference durch einen Cast bekommst und zuweist, wird nichts verlängert.Du musst es so umbiegen:
Also ist eine namenlose rvalue-reference ein rvalue (genauer, ein xvalue).
-
Sone schrieb:
nur Ausdrücke können lvalues sein.
Hä? Ein Ausdruck hat doch keinen Namen.
-
out schrieb:
Sone schrieb:
nur Ausdrücke können lvalues sein.
Hä? Ein Ausdruck hat doch keinen Namen.
Weißt du überhaupt, was lvalue bedeutet? Es ist ein Ausdruckstyp.
int a;
Nun wo a deklariert ist, ist `a
` ein lvalue. Das heißt nicht, dass das Objekt mit dem Namen a ein lvalue ist, denn das wäre falsch. Der Ausdruck "a" ist ein lvalue, denn es bezeichnet/referenziert* ein benanntes Objekt.
*: Schwer zu übersetzen, im Standard heißt es designates...
-
Sone schrieb:
Ist dir bewusst, dass eine rvalue reference (genau wie eine const lvalue reference) die Lebenszeit eines rvalues verlängert?
Nicht immer.
int&& i = 0; // ok int&& j = std::move(0); // ill-formed
-
Das ist nicht ill-formed, denn move nimmt auch rvalue Referenzen.
-
Sone schrieb:
Und das ist nicht ill-formed, denn move nimmt auch rvalue Referenzen.
Ok, nicht ill-formed, sondern UB. Das move ist in Ordnung, nur die Lebenszeitverlängerung nicht.
-
zjraw schrieb:
Sone schrieb:
Und das ist nicht ill-formed, denn move nimmt auch rvalue Referenzen.
Ok, nicht ill-formed, sondern UB.
Effektiv steht da
int&& j = static_cast<int&&>(0);
Und das ist wohldefiniertes Verhalten. Auch für Klassen. Auch hier wird die Lebenszeit verlängert.
-
Um das mit dem Standard zu erklären:
§8.5.3/5 schrieb:
Otherwise, [...] the reference shall be an rvalue reference.
If the initializer expression is an xvalue [...] and “cv1 T1” is referencecompatible with “cv2 T2” [...] then the reference is bound to the value of the initializer expression [...].#include <iostream> struct A { A(){std::cout << "C";} ~A(){std::cout << "D";} }; int main() { A&& i = static_cast<A&&>(A()); std::cout << " hi "; }
-
Sone schrieb:
Effektiv steht da
int&& j = static_cast<int&&>(0);
Nein, woher hast du den Blödsinn? std::move ist ein Funktionsaufruf und das ist wichtig.
int main() { A&& i = std::move(A()); std::cout << " hi "; }
Gibt (richtigerweise) aus
CD hi
-
Btw
A&& i = static_cast<A&&>(A());
Gibt auf clang "CD hi" aus, mit gcc "C hi D".
Ich würde meinen clang liegt hier falsch, bin mir aber nicht sicher.
-
std::move ist ein Funktionsaufruf und das ist wichtig.
Jetzt bin ich verwirrt.
Es sind doch xvalues in beiden Fällen, oder etwa nicht? Der Wert des Ausdrucks ist in beiden Fällen dasselbe Objekt, was gebunden wird. Wieso darf move nicht "geinlined" werden?
Edit: Der Unterschied liegt wohl in "value of the expression". Das wird für einen Funktionsaufruf irgendwie anders sein...
-
§5.2.2/4 schrieb:
The value of a function call is the value returned by the called function
Macht Sinn
Das macht überhaupt keinen Sinn. Dann ist der value ja derselbe wie fürstatic_cast<A&&>(A())
! Und dmait müsste dasselbe Ergebnis rauskommen, so oder so.Ich würde meinen clang liegt hier falsch, bin mir aber nicht sicher.
Hängt nun davon ab, was der "Wert" von einem
static_cast<A&&>(A())
ist.Dementsprechend:
Ich würde meinen clang liegt hier falsch, bin mir aber nicht sicher.
Anscheinend hat Clang Recht, denn es hat dasselbe Ergebnis für den Cast und move.
-
Für std::move(A()):
A() wird an A&& von der std::move-Funktion gebunden und erhält full-expression lifetime
move gibt eine Referenz auf den Parameter A() zurück
A&& wird an die Referenz gebunden
A wird gelöscht, aber die Referenz lebt noch.Beim static_cast wird so wie ich das sehe direkt zu A() gebunden, was die Lebenszeit von A() verlängert.