return by value - deep/shallow copy
-
Smartpointer bzw. RAII und das Problem der Tiefen/Flachen-Kopien sind orthogonal zueinander.
Auch wenn Du einen shared_ptr benutzt, hast Du nach wie vor nur flache Kopien.
-
Danke

Ich meinte bzgl. der smart Pointer jetzt nur Erstellen/Zerstören der Speicherbereiche und nicht die Modifikation, habe ich vergessen beizuschreiben
Gruß
-
Ne, nix. Mit C++11 Move-Konstruktoren ist das Problem doch längst gelöst, wundert mich, dass das noch niemand erwähnt hat. oO
-
Danke für deine Antwort

Kann man es denn irgendwie bewerkstelligen, dass bei der return-Anweisung gemoved wird anstatt kopiert, d.h. dass der move-Konstruktor verwendet wird anstatt der copy-Konstruktor?
-
Das passiert automatisch, sofern ein Move-Konstruktor vorhanden ist.
-
Kann man dann zusammenfassend festhalten, dass wenn man eine lokale Variable returned automatisch der move-Konstruktor gewählt wird, sofern er vorhanden ist (ansonsten der copy-Konstruktor) und wenn eine globale Variable returned wird stets der copy-Konstruktor?
Gruß

-
Ne, es gibt auch noch statische Variablen etc.
Es wird immer kopiert, es sei denn durch das return statement wird die Lebenszeit zurückgegebenen Objekts beendet, dann wird gemoved. Irgendwie logisch.
-
Ja stimmt

Vielen Dank

-
Nein das stimmt so nicht. Die Ausgabe dieses Programms
#include <iostream> class A { public: A() { std::cout << "default" << std::endl; } A( const A& ) { std::cout << "copy" << std::endl; } A( A&& ) { std::cout << "move" << std::endl; } ~A() { std::cout << "destruction" << std::endl; } }; A foo() { A a; return a; } int main() { A a = foo(); }Ist bei mir beispielsweise nur
default destructionDer compiler konstruiert das A aus foo direkt dorthin, wo es nach der Funktion gebraucht wird, d.h. es wird nie kopiert. Stattdessen übergibt main() foo() implizit einen return_ptr (oder wie man das auch nennen will), wohin das Objekt konstruiert werden soll, d.h. auf den Stackbereich von main(). Dadurch kann foo() einfach returnen und braucht a gar nicht zu kopieren oder zu moven.
Hier ist sowas nicht möglich, da je nach Pfad ein anderes Objekt returned werden kann (zumindest moved mein gcc hier):A foo() { A a; A b; if( true ) return a; else return b; }Ich meine diese Optimierung heißt 'return value optimization', danach kannst du mal googlen. Es gibt auch einige gute Tutorials zum Thema move, z.B. 'moving forward'.
-
Danke für deine Hilfe, bekommt man diese Ausgabe auch, wenn man alle Optimierungen deaktiviert?
-
Nein, RVO wird üblicherweise nur im Releasemodus durchgeführt. Du bekommst also im Debugmodus eine andere Ausgabe.
-
Bei mir schon, ja. Ich weiß aber nicht, ob diese Optimierung verpflichtend im Standard festgelegt ist, oder ob man auch standardkonform immer kopieren/moven darf.
-
Sie wird wohl nicht verpflichtend sein, wenn im Debugmodus die "normale" Ausgabe kommt.

-
Der Debug-Modus wird beim GCC mit -g eingeleitet oder? Bei mir ändert sich da nichts an der Ausgabe

-
Kann sein, dass GCC das immer an hat.
-
Ich bekomme aber die Ausgabe (mit oder ohne -g), die eigentlich im Release-Modus erscheinen sollte:
default
destruction
-
Sag ich doch. GCC macht RVO scheinbar einfach immer, warum auch nicht?
-
Daran soll's nicht scheitern.
#include <cstdlib> #include <iostream> struct A { A() { std::cout << "default" << std::endl; } A(A const &) { std::cout << "copy" << std::endl; } A(A &&) { std::cout << "move" << std::endl; } ~A() { std::cout << "destruction" << std::endl; } }; A foo() { A a, b; // RVO verhindern. return std::rand() % 2 == 0 ? a : b; } int main() { A a = foo(); }gibt bei mir
default default copy destruction destruction destructionMove gibt's mit
return std::move(std::rand() % 2 == 0 ? a : b);a in main wird allerdings von gcc nach wie vor direkt initialisiert. Grundlage ist g++ 4.7.0 mit -std=c++11.
-
MatheStein schrieb:
Der Debug-Modus wird beim GCC mit -g eingeleitet oder? Bei mir ändert sich da nichts an der Ausgabe

-g erzeugt nur Debug-Symbole.
-O0 setzt die Optimierungen auf 0, also Debug-Build. -O1, -O2, -O2.5, -Os und -O3 erzeugen Realese-Builds.
-
Bei mir bleibt die Ausgabe stets gleich, auch mit -O0