C++ Pendant zu Java Objekt Referenz
-
@CppConst sagte in C++ Pendant zu Java Objekt Referenz:
Und wenn man sich nicht auf RVO verlassen möchte, was kann man dann empfehlen?
Sich auf RVO zu verlassen.
-
Ist halt nicht einfach, wenn man von Java auf C++ umsteigt und bei mir in Java werden haufenweise Objekte in Methoden erzeugt und dann einfach zurückgegeben. Und bei C++ habe ich eben gelesen, dass es da zu Kopien kommen kann. Das versuche ich im Vorfeld schon sicher zu eliminieren und dachte da gibt es was Allgemeines für.
-
@CppConst sagte in C++ Pendant zu Java Objekt Referenz:
Das versuche ich im Vorfeld schon sicher zu eliminieren
Ja. Lass das. Das ist vergebene Liebesmüh'. Schreib' schönen(tm) Code.
-
Ok, dann kümmere ich mich darum wenn es Probleme gibt und erzeuge erstmal einfach einen std::string und geben den so wie er ist mit return zurück.
-
Gute Idee.
-
Wenn es um String geht... https://www.c-plusplus.net/forum/topic/347040/einen-string-an-eine-funktion-übergeben
-
@Helmut-Jakoby Es geht um Rückgabe. Aber, gratuliere, du hast deinen Werbelink wieder erfolgreich angebracht.
-
Damit RVO greifen kann, muss meine Objekt aber einen Move Konstruktor haben, oder?
-
@CppConst sagte in C++ Pendant zu Java Objekt Referenz:
Damit RVO greifen kann, muss meine Objekt aber einen Move Konstruktor haben, oder?
Nein.
Move ist auch Arbeit, wenn auch oft weniger als eine Kopie. Aber wenn es geht, ist "gar nichts tun" besser als move. Move passiert, wenn "nichts tun" nicht geht.
Siehe auch https://youtu.be/hA1WNtNyNbo
-
Bzw. s. Copy elision
-
@CppConst sagte in C++ Pendant zu Java Objekt Referenz:
Damit RVO greifen kann, muss meine Objekt aber einen Move Konstruktor haben, oder?
Bei RVO + copy-elision wird das Objekt direkt dort erstellt wo es dann nach dem Funktionsaufruf "weiterleben" soll.
Foo makeFoo() { Foo f{"blah"}; // 1 f.something(1); f.somethingElse(1, 2, 3); return f; // Hier KEIN std::move() - mit move würde man NRVO _verhindern_ } void fun() { Foo foo{makeFoo()}; // 2 }
Das Objekt das in (1) erstellt wird, wird also direkt im Speicher der Variable von Zeile (2) erstellt. Hier wird weder ein Move-Konstruktor noch ein Copy-Konstruktor verwendet.
-
Danke für die genaue Erklärung, so langsam begreife ich es. Ist nicht so einfach C++ richtig zu verstehen. Ich habe zwar schon einige Sachen mit C++ gemacht, habe mir allerdings über solche Dinge keine Gedanken gemacht, bis ich so ein CppCon Video gesehen hatte, wo es darum ging wie man Overhead vermeiden kann, dann kamen die Fragen und nun möchte ich C++ besser kennen lernen.
-
Ergänzung:
Foo makeFoo() { Foo f{"blah"}; // 1 f.something(1); f.somethingElse(1, 2, 3); return f; // Hier KEIN std::move() - mit move würde man NRVO _verhindern_ }
Tatsächlich garantierte der Standard vor guaranteed copy elision (also vor C++17) ab C++11, dass der identifier
f
ein rvalue ist. D.h.move(f)
war implizit. Es haette also schon rein technisch niemals geholfen, das zu schreiben (abgesehen davon, dass NRVO lange vor guaranteed copy elision implementiert war).
-
Spannend wird es nur hier:
Foo makeFoo(bool condition) { Foo f1{"blah"}; Foo f2{"blubberdieblubb"}; // [code...] // a) return condition ? f1 : f2; // b) return std::move(condition ? f1 : f2); }
Hier ist rechts ja ein ?-:-Konstrukt. Mit so einer Konstruktion verbaut man sich das automatische move.
-
Also theoretisch könnte man einen absoluten Grossteil der Verwendungen eines automatischen Objektes in return statements durch einen Move ersetzen. Es gibt aber eben auch Ausnahmen (überwiegend realitätsferner Natur...) und deshalb ist es nur fuer simple Identifier gegeben.
-
@Columbo sagte in C++ Pendant zu Java Objekt Referenz:
Es haette also schon rein technisch niemals geholfen, das zu schreiben
Richtig. Ich hab das Kommentar bloss dazugeschrieben weil es in dem Fall nicht nur unnütz ist sondern sogar schadet.
-
@hustbaer ich weiss, deshalb ja auch als "Ergänzung"
-
@wob sagte in C++ Pendant zu Java Objekt Referenz:
Spannend wird es nur hier:
Foo makeFoo(bool condition) { Foo f1{"blah"}; Foo f2{"blubberdieblubb"}; // [code...] // a) return condition ? f1 : f2; // b) return std::move(condition ? f1 : f2); }
Hier ist rechts ja ein ?-:-Konstrukt. Mit so einer Konstruktion verbaut man sich das automatische move.
Also wenn nicht klar ist welches Objekt zurückgegeben wird, ist es sinnvoller mit move zu arbeiten um Kopien zu vermeiden?
-
@CppConst sagte in C++ Pendant zu Java Objekt Referenz:
Also wenn nicht klar ist welches Objekt zurückgegeben wird, ist es sinnvoller mit move zu arbeiten um Kopien zu vermeiden?
Im Allgemeinen vermutlich ja.
Wobei man den Code auch u.U. umschreiben kann. Wenn
f1
undf2
in[code...]
nicht gebraucht werden, dann wäre es besser zu schreiben:Foo makeFoo(bool condition) { // [code...] if (condition) return {"blah"}; else return {"blubberdieblubb"}; }
Denn dann greift wieder RVO, und man spart sich das 2. unnötige
Foo
Objekt zu erzeugen. (Diesmal wirklich RVO und nicht NRVO.)