Psycho hat geschrieben:std::move finde ich an der Stelle schlecht,
denn das möchte ich nicht jedesmal hinschreiben
(und das nicht nur aus Faulheit).
An welcher Stelle?
move müsstest du allenfalls anstatt
new hinschreiben, ich sehe da absolut kein Problem. Tatsächlich solltest du auf
move aber sogar ganz verzichten, siehe unten.
Psycho hat geschrieben:Bitte unter der Annahme, dass Copy-Elison nicht garantiert ist.
Copy Elision ist zwar nicht garantiert, aber so zuverlässig und effektiv, dass ich sie auf keinen Fall außen vor lassen würde.
Wie dot sagt, hängt die Wahl sehr vom Kontext ab. Ich nutze den Freispeicher eigentlich nur zur einmaligen Erzeugung von Objekten, die eine Identität haben (also von anderen über eine Adresse referenziert werden). Haben solche Objekte Zustand, so werden diese im Anschluss meist mit Variante 3 (Ausgabeparameter oder implizit über
this) manipuliert. Manchmal hast du auch keine Wahl, nämlich immer dann, wenn du Interface-Zeiger auf polymorphe Objekte zurückgeben musst. In diesem Fall kommst du um den Freispeicher gar nicht herum.
Davon abgesehen verlasse ich mich bei Objekten, deren Kopieraufwand (mit wie ohne
move) nicht unverhältnismäßig hoch wäre, praktisch immer auf implizites
move und Copy Elision. Wenn du in einer beliebigen Funktion ein zurückzugebendes Objekt als allererstes anlegst, kannst du dir praktisch sicher sein, dass bei der Rückgabe keine Kopie stattfinden wird. Ist das mal nicht möglich, und Copy Elision dadurch für den Compiler keine Option,
muss er stattdessen (vom Standard
garantiert) bei der Rückgabe automatisch auf implizites
move umsteigen.
Auf Aufruferseite wird so wie so immer automatisch entweder Copy Elision (bei Initialisierung) oder ein implizites
move (Move Assignment) stattfinden, egal was du in der Funktion tust. Im Übrigen ist es deshalb ratsam, Funktionsergebnisse immer direkt in einer Initialisierung entgegenzunehmen.
Hier ein Testlauf mit gcc, MSVC++10 liefert dasselbe:
http://ideone.com/KVnyF
Man beachte, dass ein manuelles
move bei der Rückgabe Copy Elision verhindert. Das heißt konkret, dass du bei der Rückgabe von Objekten weder im
return-Statement in der Funktion noch an der Stelle des Aufrufs außerhalb der Funktion jemals manuell
move aufrufen solltest. Es wird garantiert, dass automatisch alles so optimal wie möglich läuft, und bei Verfügbarkeit von Move Semantics garantiert
nie eine Kopie stattfindet.
Nachtrag zu den Zeigern: unique_ptr ist bei Rückgabe über den Freispeicher wohl immer die richtige Wahl, wenn du nicht von vorneherein weißt, dass geteilte Besitzverhältnisse zu erwarten sind.
Nachtrag 2: Manuelles
move unterdrückt Copy Elision, Beitrag entsprechend angepasst.
Nachtrag 3: Komplettierter Testlauf:
http://ideone.com/KVnyF
Nachtrag 4: Implizites
move auf Aufruferseite ist übrigens vom Standard garantiert, sollte das nicht klar sein.
Zu implizitem move im return-Statement ohne Copy Elision finde ich leider gerade nichts.
Nachtrag 5: Auch im
return-Statement wird an Stellen, an denen Copy Elision erlaubt ist, implizites
move garantiert. Beitrag entsprechend aktualisiert.