C++11 Frage
-
Gut, jetz wird das schon etwas klarer.
int&& i = getInt( );Ist also eine Referenz auf das Return Value des Calls. Es wird nichts kopiert.
Aber wie merkt er sich das?MfG
BTW: Wäre es nicht das selbe wie das hier?
#include <iostream> int* get( ) { return new int( 19 ); } int main( int argc, char* argv[ ] ) { int i = *get( ); return 0; }
-
yihaaa schrieb:
BTW: Wäre es nicht das selbe wie das hier?
Nein. Bei deinem Beispiel wird der in
get()am Heap angeforderteintnachikopiert und bleibt seinerseits als Speicherlöchli übrig.
-
Ja gut, man müsste es eben noch löschen.
MfG
-
Auch dann würd' kopiert!
-
Cyres schrieb:
Die Begriffe sind eigentlich selbsterklärend: && ist eine Referenz auf ein rvalue, also in etwa
Foo&& i = Foo(10); Foo j = i;Der Default-Konstruktor von Foo wird in der ersten Zeile aufgerufen, der Move-Konstruktor in der zweiten Zeile.
Ich hab es zwar nicht getestet, aber da i einen Namen hat, wird denke ich der normale Copy-Contruktor aufgerufen...
Zudem meine ich mich zu erinnern, dass man einen Rückgabewert (hier halt der Konstruktor) nicht als rvalue-Referenz speichert.
Du möchtest wohl eher etwas wie:
Foo i(10); Foo j = std::nove(i);Gruß,
XSpilleWenn ich völlig falsche liege, korrigiert mich bitte...
-
Benannte RValue Referenzen sind LValues.
-
Hier der 'Beweis' (ohne Optimierungen kompilieren!):
#include <string> #include <iostream> struct Foo{ Foo(int v) : i(new int(v)){ } Foo(Foo&& foo) : i(foo.i) { foo.i = 0; std::cout << "move" << std::endl; } Foo(const Foo& foo) : i(new int(*foo.i)) { std::cout << "copy" << std::endl; } ~Foo(){ delete i; } int* i; }; int main(){ Foo&& i = Foo(10); // <-- Hier Foo j = i; Foo i2 = Foo(10); Foo j2 = std::move(i2); }copy
moveWie Kellerautomat gemeint hat: sobald er einen Namen hat, ist es wieder ein lvalue...
Aber vielleicht bestätigt mir noch jemand, dass man die markierte Zeile ebenfalls nicht so verwenden sollte...
-
Die Zeile ist zwar nicht besonders sinnvoll, aber auch nicht falsch.
-
Also ich hätte z.B. erwartet, dass dieser Code crashed:
void fill_stack(int i){ if(i<1000){ std::cout << i <<std::endl; fill_stack(++i); } } Foo f(){ return Foo(10); } int main(){ Foo&& i = f(); std::cout << *i.i << std::endl; fill_stack(0); Foo j = i; std::cout << *j.i << std::endl; }Also Foo(10) liegt auf dem Stack und danach wird der Stack durch den Funktionsaufruf überschrieben...
Und eine rvalue-Referenz, ist ja auch nur eine Referenz...Ich vermute es liegt nur an 'Optimierungen' des Compilers?
-
So funktionieren RValue Referenzen aber nicht. Die Lebenszeit des temporaeren Objektes wird bis zum Scopeende verlaengert, genau wie wenn du eine LValue Referenz auf const verwendet haettest.
-
Kellerautomat schrieb:
So funktionieren RValue Referenzen aber nicht. Die Lebenszeit des temporaeren Objektes wird bis zum Scopeende verlaengert, genau wie wenn du eine LValue Referenz auf const verwendet haettest.
Stimmt...
Hab ich auch schonmal gehört!!! THX 
-
@yihaaa Mit Basistypen machen Rvalue-Referenzen ja auch wenig Sinn. (Zumindest fällt mir da keine Anwendung ein.) Aber die übergibst du ja auch nicht per Referenz (außer du willst sie verändern) aber der Punkt ist, dass kopieren nichts kostet. Interessant sind RValue Referenzen z.B. bei Containern wie std::vector. Angenommen du hast eine Klasse, die im Konstruktor einen std::vector will und den dann abspeicherst. In C++03 hätte man jetzt eine const& genommen, und den vector dann kopiert. Wenn der vector sonst aber garnicht mehr gebraucht wurde, war das eine unnötige Kopie. Jetzt kann man den vector aber "moven", dadurch wird die Aktion dann etwa so teuer wie das Kopieren eines Pointers.
-
Eher so teuer wie das Kopieren einer struct mit drei Zeigern

-
@cooky451: Ja das mit den Basistypen habe ich jetz verstanden. Trotzdem vielen Dank für die Erklärung.
Ist es richtig, dass std::move einfach nur ein typecast ausführt? Sowas in der Art?
reinterpret_cast< Type&& >( x );MfG
-
yihaaa schrieb:
@cooky451: Ja das mit den Basistypen habe ich jetz verstanden. Trotzdem vielen Dank für die Erklärung.
Ist es richtig, dass std::move einfach nur ein typecast ausführt? Sowas in der Art?
reinterpret_cast< Type&& >( x );MfG
Es ist ein cast, allerdings kein reinterpret_cast, sondern etwas normales (static_cast). Wieso wird eigentlich bei Fragen immer gleich reinterpret_cast ausgepackt?
Sieht also ungefähr so aus:
template <typename T> auto move(T&& x) noexcept -> typename std::remove_reference<T>::type&& { return static_cast<typename std::remove_reference<T>::type&&>( x ); }
-
Okay, braucht man doch dann nur um bei einer Klasse den Move Konstruktor sicher aufrufen zu können?
MfG
Edit: Weiß ich nicht

-
Warum definiert man move nicht eigentlich einfach so?
template <typename T> T&& move(T& x) { return static_cast<T&&>(x): }Dass es dann mit RValues nicht funktioniert, interessiert doch keinen.
-
Kellerautomat schrieb:
Warum definiert man move nicht eigentlich einfach so?
template <typename T> T&& move(T& x) { return static_cast<T&&>(x): }Dass es dann mit RValues nicht funktioniert, interessiert doch keinen.
Dann geht aber doch z.B. das hier nicht mehr, oder?
string str = "123"; int z; istringstream(str) >> z;
-
Wo ist hier ein move?
-
Kellerautomat schrieb:
Warum definiert man move nicht eigentlich einfach so?
template <typename T> T&& move(T& x) { return static_cast<T&&>(x): }Dass es dann mit RValues nicht funktioniert, interessiert doch keinen.
Das hatte ich mich auch mal gefragt; denn es ist ja sogar eher schädlich, move auf einem Rvalue aufzurufen, da dadurch copy elision unterdrückt wird. Aber ich kann mir vorstellen, dass man in manch generischem Code nicht immer weiß, ob ein Funktionsaufruf (z.B. eine Iterator-Dereferenzierung) ein Lvalue oder Rvalue-Ausdruck ist. Man würde ein Lvalue erwarten, aber es gibt ja auch Iteratoren von "lazy sequences" die den Wert erst dann ausrechnen, wenn man ihn haben will und das ist dann ggf. ein temporäres Objekt...