Es verwendet , um beste Praxis in der Regel empfohlen werden 1 zu verwenden Pass von const ref für alle Typen , mit Ausnahme von eingebauten Typen ( char
, int
, double
, etc.), für Iteratoren und Funktionsobjekte (Lambda - Ausdrücke, Klassen die sich aus std::*_function
).
Dies galt insbesondere vor der Existenz der Bewegungssemantik . Der Grund ist einfach: Wenn Sie einen Wert übergeben haben, musste eine Kopie des Objekts erstellt werden. Mit Ausnahme sehr kleiner Objekte ist dies immer teurer als das Übergeben einer Referenz.
Mit C ++ 11 haben wir die Bewegungssemantik gewonnen . Kurz gesagt, die Bewegungssemantik ermöglicht es, dass ein Objekt in einigen Fällen "nach Wert" übergeben werden kann, ohne es zu kopieren. Dies ist insbesondere dann der Fall, wenn das Objekt, das Sie übergeben, ein r-Wert ist .
An sich ist das Bewegen eines Objekts immer noch mindestens so teuer wie das Übergeben als Referenz. In vielen Fällen kopiert eine Funktion ein Objekt jedoch trotzdem intern - dh sie übernimmt das Eigentum an dem Argument. 2
In diesen Situationen haben wir den folgenden (vereinfachten) Kompromiss:
- Wir können das Objekt als Referenz übergeben und dann intern kopieren.
- Wir können das Objekt als Wert übergeben.
"Wert übergeben" bewirkt weiterhin, dass das Objekt kopiert wird, es sei denn, das Objekt ist ein r-Wert. Im Falle eines r-Werts kann das Objekt stattdessen verschoben werden, so dass der zweite Fall plötzlich nicht mehr "kopieren, dann verschieben", sondern "verschieben, dann (möglicherweise) wieder verschieben" lautet.
Bei großen Objekten, die geeignete Verschiebungskonstruktoren implementieren (wie Vektoren, Zeichenfolgen usw.), ist der zweite Fall dann weitaus effizienter als der erste. Daher wird empfohlen, den Wert " Übergeben" zu verwenden, wenn die Funktion den Besitz des Arguments übernimmt und der Objekttyp ein effizientes Verschieben unterstützt .
Eine historische Anmerkung:
Tatsächlich sollte jeder moderne Compiler in der Lage sein, herauszufinden, wann das Übergeben von Werten teuer ist, und den Aufruf implizit so zu konvertieren, dass er nach Möglichkeit eine const ref verwendet.
In der Theorie. In der Praxis können Compiler dies nicht immer ändern, ohne die binäre Schnittstelle der Funktion zu beschädigen. In einigen speziellen Fällen (wenn die Funktion inline ist) wird die Kopie tatsächlich entfernt, wenn der Compiler herausfinden kann, dass das ursprüngliche Objekt durch die Aktionen in der Funktion nicht geändert wird.
Im Allgemeinen kann der Compiler dies jedoch nicht feststellen, und das Aufkommen der Verschiebungssemantik in C ++ hat diese Optimierung viel weniger relevant gemacht.
1 ZB in Scott Meyers, Effektives C ++ .
2 Dies gilt insbesondere häufig für Objektkonstruktoren, die Argumente verwenden und intern speichern, um Teil des Status des konstruierten Objekts zu sein.