In fast jedem Beitrag, den ich auf SO sehe und an dem a beteiligt ist std::initializer_list
, neigen die Leute dazu, einen std::initializer_list
Wert zu übergeben. Nach diesem Artikel:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
man sollte den Wert übergeben, wenn man eine Kopie des übergebenen Objekts erstellen möchte. Aber das Kopieren von a std::initializer_list
ist keine gute Idee
Durch das Kopieren von a werden
std::initializer_list
die zugrunde liegenden Objekte nicht kopiert. Es ist nicht garantiert, dass das zugrunde liegende Array existiert, nachdem die Lebensdauer des ursprünglichen Initialisierungslistenobjekts abgelaufen ist.
Warum wird eine Instanz davon oft nach Wert übergeben und nicht beispielsweise nach dem const&
, was garantiert keine unnötige Kopie ergibt?
Antworten:
Es wird als Wert übergeben, weil es billig ist.
std::initializer_list
Da es sich um einen dünnen Wrapper handelt, wird er höchstwahrscheinlich als Zeigerpaar implementiert, sodass das Kopieren (fast) so billig ist wie das Übergeben als Referenz. Außerdem führen wir keine Kopie durch, sondern (normalerweise) eine Verschiebung, da das Argument in den meisten Fällen ohnehin aus einem temporären Argument aufgebaut ist. Dies hat jedoch keinen Einfluss auf die Leistung - das Verschieben von zwei Zeigern ist genauso teuer wie das Kopieren.Andererseits kann der Zugriff auf die Elemente einer Kopie schneller sein, da wir eine zusätzliche Dereferenzierung (die der Referenz) vermeiden.
quelle
const&
wird jedoch nicht unbedingt als Zeiger implementiert (wenn ich mich richtig an den Standard erinnere), könnte es auch eine Art Alias sein.std::initializer_list
von Wert. Das ist ein sehr starker Hinweis. Wenn die Standardbibliothek Pass-by-Value verwendet, können Sie sicher dasselbe tun, denn selbst wenn es ineffizient wäre, würden Sie diesen Effekt trotzdem erleiden. Darüber hinaus gibt der Standard explizite Hinweise zur Implementierung (§ 18.9 / 2: „Ein Zeigerpaar oder ein Zeiger plus eine Länge wären offensichtliche Darstellungen fürinitializer_list
.“).initializer_list
es zwei Iteratoren. Die gesamte STL basiert auf der Annahme, dass das Kopieren von Iteratoren billig ist. Es gibt viel mehr Argumente für die Übergabe von Werten als die von Konrad vorgebrachten - das Wichtigste ist wahrscheinlich, dass der übergebene Wert ein temporärer Wert mit einem trivialen Destruktor ist und daher direkt konstruiert werden kann, da das Argument wahrscheinlich der ist am aussagekräftigsten --- aber Überlegungen zur Leistung können nicht gegen die Übergabe von Werten geltend gemacht werden.Wahrscheinlich aus den gleichen Gründen werden Iteratoren fast immer als Wert übergeben: Das Kopieren eines Iterators wird als "billig" angesehen. Im Fall von
initializer_list
gibt es auch die Tatsache, dass die meisten Instanzen temporär mit trivialen Destruktoren sind, so dass der Compiler sie direkt dort erstellen kann, wo er das Funktionsargument ohne Kopie platziert. Schließlich gibt es die Tatsache, dass die aufgerufene Funktion wie Iteratoren wahrscheinlich den Wert ändern möchte, was bedeutet, dass sie ihn lokal kopieren müsste, wenn sie von einem Verweis auf const übergeben würde.BEARBEITEN:
Nur zur Verallgemeinerung: Die Standardbibliothek geht allgemein davon aus, dass es besser ist, Iteratoren, initializer_lists und funktionale Objekte nach Wert zu übergeben. Daher sollten Sie sicherstellen, dass alle von Ihnen entworfenen Iteratoren, Iteratorlisten oder Funktionsobjekte billig zu kopieren sind, und Sie sollten in Ihrem eigenen Code davon ausgehen, dass sie billig zu kopieren sind. Die traditionelle Regel, wann Verweise auf const und wann Wert verwendet werden sollen, sollte wahrscheinlich geändert werden, um dies widerzuspiegeln:
quelle
std::function<>
Beispiel eine Instanz kopieren ? Sicherlich ist es nicht billig zu kopieren.std::function
mit einem großenstd::vector
Inneren ist keine gute Idee.)std::function
: Das Ergebnis vonstd::bind
kann voneinander verschoben werden, und durch Verschieben werden gebundene Argumente verschoben. Ich habe debuggt, um zu überprüfen, ob dies der Fall ist. Daher sollte es relativ effizient sein, sich vonstd::function
's zu entfernen , die beispielsweise gebundene Vektoren enthalten - da Vektoren effizient verschoben werden können.std::function
s nicht billig zu kopieren sind, sind andere Arten von Funktoren normalerweise ziemlich kostenlos.