rvalue reference
-
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.
-
In beiden Fällen sind es xvalues. Sowohl
move(...)
ist ein xvalue als auch der Cast.Das heißt in beiden Fällen trifft der selbe Standardabschnitt zu, und zwar der:
then the reference is bound to the value of the initializer expression
Nun kann der einzige Unterschied nur in value of the initializer expression liegen. Und der ist offensichtlich derselbe, da der Standard das für Funktionsaufrufe definiert.
-
Ok, sieht so aus, als wäre clang doch richtig
Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_-
cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The
effect of such an explicit conversion is the same as performing the declaration and initialization and then
using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and
only if the initialization uses it as a glvalue.Also
A&& i = static_cast<A&&>(A()); // <=> A&& i = { A&& a( A() ), t }; // A() wird am Ende dieser Zeile destructed, die Referenz überlebt
Sone schrieb:
In beiden Fällen sind es xvalues. Sowohl
move(...)
ist ein xvalue als auch der Cast.Irrelevant.
Sone schrieb:
Das heißt in beiden Fällen trifft der selbe Standardabschnitt zu, und zwar der:
then the reference is bound to the value of the initializer expression
Ja, A&& ist die value. Die Lebenszeit von A&& wird verlängert, aber nicht die von dem A auf das referenziert wird.
Sone schrieb:
Nun kann der einzige Unterschied nur in value of the initializer expression liegen. Und der ist offensichtlich derselbe, da der Standard das für Funktionsaufrufe definiert.
static_cast ist kein Funktionsaufruf.
-
Irrelevant
Nein, relevant.
Ja, A&& ist die value. Die Lebenszeit von A&& wird verlängert, aber nicht die von dem A auf das referenziert wird.
Ja, das ist der Punkt wo ich haperte. Ich dachte der "Wert" kann nur ein Objekt sein.
static_cast ist kein Funktionsaufruf.
Nein, aber er Ausdruck mit
static_cast
ist der Rückgabewert vonmove
. Und nun siehe den Standardabschnitt den ich zu Funktionsaufrufen gepostet habe.Anscheinend hat Clang Recht, denn es hat dasselbe Ergebnis für den Cast und move.
-
A&& i = { A&& a( A() ), t };
Was bitte soll denn das sein?
Edit: Oh, tut mir Leid, das ist ja Pseudocode.
-
Sone schrieb:
Nein, aber
static_cast
ist der Rückgabewert vonmove
.Das spielt aber keine Rolle!!
Wäre static_cast<T&&>(x) definiert als "rvalue-referenz auf x" würde sich static_cast anders verhalten als std::move, weil std::move eine Funktion ist und static_cast nicht. Ich gebs auf mit dir zu diskutieren.
-
Wäre static_cast<T&&>(x) definiert als "rvalue-referenz auf x" würde sich static_cast anders verhalten als std::move, weil std::move eine Funktion ist und static_cast nicht.
---
Es verhält sich ja deswegen gleich, weil der Wert eines Funktionsaufrufs derselbe ist, wie der des zurückgegebenen Wertes. Undmove
ist genauso definiert, dass esstatic_cast<T&&>(t)
zurückgibt.
Daher hatmove
in dieser Hinsicht immer denselben Effekt wiestatic_cast<T&&>(t)
.Und damit hatte ich völlig Recht:
Effektiv steht da
int&& j = static_cast<int&&>(0);
Ich gebs auf mit dir zu diskutieren.
Ich nicht, aber wenn du müde bist...
-
Irgendwie zweifel ich an einem Sprachstandard, den man fast wortwörtlich auswendig lernen muss, dmait man das Verhalten der Sprache interpretieren kann.
-
otze schrieb:
Irgendwie zweifel ich an einem Sprachstandard, den man fast wortwörtlich auswendig lernen muss, dmait man das Verhalten der Sprache interpretieren kann.
Deswegen ist C++ nur für die Verrückten.
-
Sone schrieb:
Und damit hatte ich völlig Recht:
Effektiv steht da
int&& j = static_cast<int&&>(0);
Jo, bis dahin schon.
Sone schrieb:
Und das ist wohldefiniertes Verhalten. Auch für Klassen. Auch hier wird die Lebenszeit verlängert.
Das war hingegen falsch. Falls j weiter verwendet wird hat man UB.
-
Ja, das stimmt.
Signatur angepasst.
-
Sone schrieb:
otze schrieb:
Irgendwie zweifel ich an einem Sprachstandard, den man fast wortwörtlich auswendig lernen muss, dmait man das Verhalten der Sprache interpretieren kann.
Deswegen ist C++ nur für die Verrückten.
03 war noch lange nicht so schlimm wie 11.
-
otze schrieb:
03 war noch lange nicht so schlimm wie 11.
Gilt genauso für C++03.
struct A { A(){std::cout << "C";} ~A(){std::cout << "D";} }; A const& hi(A const& a) { return a; } int main() { { A const& i = hi(A()); std::cout << " hi "; } std::cout << "\n--\n"; { A const& i = static_cast<A const&>(A()); std::cout << " hi "; } } /* Ausgabe: CD hi -- C hi D */
Ich verstehs aber immer noch nicht. Damit wäre nämlich static_cast tatsächlich anders als move.
-
Da wird wohl einfach der Compiler falsch liegen. Genau wie selbst die neuste veröffentlichte Variante des GCCs nicht standardkonform ist. Ich würde es auf 4.9 testen, bin aber zu faul um umzubooten.
Hast du obiges Beispiel auf Clang getestet?
03 war noch lange nicht so schlimm wie 11.
Auch C++03 hatte seine Hardcore-Teile.
-
Sone schrieb:
Hast du obiges Beispiel auf Clang getestet?
Auf g++ 4.9 sowie auf clang 3.4. Verhält sich aber auch auf älteren Versionen so.
-
Wenn das tatsächlich nicht konform ist, dann müsste man beiden Compilern ein Ticket schreiben.
-
Sone schrieb:
Auch C++03 hatte seine Hardcore-Teile.
Aber irgendwie wurden das mit C++11 nur mehr, nicht weniger. Dieser ganze RValuee kram ist ohne Standard lesen nicht ordentlich erklärbar, weil es da echt um details geht.