Unterschied xvalue and rvalue
-
Hallo zusammen,
wozu muss man zwischen xvalue und rvalue unterscheiden?
http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues
[Example: The result of calling a function whose return type is an rvalue reference is an xvalue.]
Wann macht es denn Sinn eine rvalue reference zu returnen?
Gemeint sind doch derartige Funktionen, oder?Foo&& bar();
Beim Aufruf von
Foo bar();
wird das zurückgegebene Foo doch eh zum rvalue...
Ich hoffe ihr könnt Licht ins Dunkle bringen
Gruß,
XSpille
-
Soweit ich das überblicke, geht es dabei um std::forward und std::move. Xvalues müssen keine prvalues sein, was dann wichtig ist, wenn glvalues für Move-Semantik herangezogen werden sollen. Etwa im Fall von
std::vector<int> v1 { 1, 2, 3, 4 }; std::vector<int> v2(std::move(v1)); // Hier ist kein prvalue zu haben!
Ohne eine Überbrückungskategorie zwischen glvalues und rvalues wäre das schwer zu formulieren.
-
seldon schrieb:
Soweit ich das überblicke, geht es dabei um std::forward und std::move. Xvalues müssen keine prvalues sein, was dann wichtig ist, wenn glvalues für Move-Semantik herangezogen werden sollen. Etwa im Fall von
std::vector<int> v1 { 1, 2, 3, 4 }; std::vector<int> v2(std::move(v1)); // Hier ist kein prvalue zu haben!
Ohne eine Überbrückungskategorie zwischen glvalues und rvalues wäre das schwer zu formulieren.
Danke dir!
Nach dem Aufruf von std::move ist das Ergebnis kein prvalue?
-
move ist im Wesentlichen ein static_cast<T&&>, gibt somit eine RValue Referenz zurück, die damit ein XValue ist.
-
314159265358979 schrieb:
move ist im Wesentlichen ein static_cast<T&&>, gibt somit eine RValue Referenz zurück, die damit ein XValue ist.
A prvalue (“pure” rvalue) is an rvalue that is not an xvalue.
Ich denke dein "damit" kann dann aber so nicht stimmen.
Du folgerst ja gerade rvalue reference => xvalue, oder?Und es gibt ja Fälle (prvalue), wo das nicht der Fall ist.
Oder habe ich dich falsch verstanden?
-
Da die RValue Referenz ein Rückgabewert ist, ist sie ein XValue.
-
XSpille schrieb:
wozu muss man zwischen xvalue und rvalue unterscheiden?
Xvalue ist spezieller als Rvalue.
Rvalue ist entweder Xvalue oder PRvalue.
Warum wir diese Terminologie haben und zwischen den Dingen unterscheiden? Weil es auch unterschiedliche Dinge sind. Hätten wir diese Begriffe nicht, müsstest Du beim Aufschreiben der Regeln im C++ Standard viele Ausnahmen machen.Bei L<->R geht es darum, ob ein Objekt einfach so verändert werden darf, weil's keinen stören würde (R) oder eben nicht (L).
Bei GL<->PR geht es um die Identität. GLvalues können einen abstrakten oder unvollständigen Typ haben, sie haben einen festen Platz im Speicher und beziehen sich immer auf ein Objekt, auch bei Typen wie
int
. Auf PRvalues trifft das nicht zu. Das sind kurzlebige (im automatischen Speicher lebende) Objekte oder auch einfach nur Werte (z.B. beim Typint
).Xvalues sind dann interessant, wenn man aus einem Lvalue ein Rvalue machen will, was sich immer noch auf dasselbe Objekt bezieht. (ein Xvalue ist ein Rvalue). Verwendung findet das bei std::move und std::forward.
XSpille schrieb:
Wann macht es denn Sinn eine rvalue reference zu returnen?
Gemeint sind doch derartige Funktionen, oder?Foo&& bar();
Ja. Sinn macht das recht selten. Die zwei bekanntesten Beispiele sind, wie gesagt, std::move und std::forward. Sonst könnte es noch in so einer Situation Sinn machen:
class foo { std::string s; public: ... string const& get() const& {return s;} string && get() && {return std::move(s);} ... }; foo quelle(); int main() { string x = quelle().get(); }
quelle()
ist ein PRvalue. Dementsprechend wird beiget()
die zweite Überladung gewählt. Dementsprechend istquelle().get()
ein Xvalue. Dementsprechend wird der String aus dem temporären foo-Objekt nach x "gemoved" und nicht kopiert.Aber so toll finde ich diesen Anwendungsfall jetzt auch nicht. Man könnte auch folgendes schreiben:
... string get() const& {return s;} string get() && {return std::move(s);} ...
Statt einer Referenz auf ein internes Element wird ein neues Objekt zurück gegeben.
XSpille schrieb:
Beim Aufruf von
Foo bar();
wird das zurückgegebene Foo doch eh zum rvalue...
Vor allem ist das, was zurück gegeben wird ein komplett neues Objekt (sofern hier kein RVO stattfand) und keine Referenz.
k.k.
-
DANKE krümelkacker!