Wie viele Daten werden kopiert, wenn ein std :: vector in einer Funktion zurückgegeben wird und wie groß die Optimierung sein wird, um den std :: vector im Free-Store (auf dem Heap) zu platzieren und stattdessen einen Zeiger zurückzugeben, dh:
std::vector *f()
{
std::vector *result = new std::vector();
/*
Insert elements into result
*/
return result;
}
effizienter als:
std::vector f()
{
std::vector result;
/*
Insert elements into result
*/
return result;
}
?
c++
return-value
stdvector
Morten
quelle
quelle
f
?Antworten:
In C ++ 11 ist dies der bevorzugte Weg:
Das heißt, Rückgabe nach Wert.
Hat in C ++ 11
std::vector
eine Verschiebungssemantik, was bedeutet, dass der in Ihrer Funktion deklarierte lokale Vektor bei der Rückgabe verschoben wird und in einigen Fällen sogar die Verschiebung vom Compiler entfernt werden kann.quelle
return std::move(v);
wird die Bewegungselision deaktiviert, selbst wenn dies nur mit möglich warreturn v;
. Letzteres ist also bevorzugt.Sie sollten nach Wert zurückkehren.
Der Standard verfügt über eine spezielle Funktion zur Verbesserung der Effizienz der Wertrendite. Es heißt "Copy Elision" und in diesem Fall "Named Return Value Optimization (NRVO)".
Compiler müssen es nicht implementieren, aber dann wieder Compiler nicht haben Funktion zu implementieren inlining (oder jede Optimierung überhaupt durchführen). Die Leistung der Standardbibliotheken kann jedoch ziemlich schlecht sein, wenn Compiler nicht optimieren und alle seriösen Compiler Inlining und NRVO (und andere Optimierungen) implementieren.
Wenn NRVO angewendet wird, wird der folgende Code nicht kopiert:
Der Benutzer möchte dies jedoch möglicherweise tun:
Die Kopierelision verhindert hier keine Kopie, da es sich eher um eine Zuweisung als um eine Initialisierung handelt. Sie sollten jedoch weiterhin nach Wert zurückkehren. In C ++ 11 wird die Zuweisung durch etwas anderes optimiert, das als "Verschiebungssemantik" bezeichnet wird. In C ++ 03 verursacht der obige Code eine Kopie, und obwohl theoretisch ein Optimierer dies möglicherweise vermeiden kann, ist es in der Praxis zu schwierig.
myvec = f()
In C ++ 03 sollten Sie stattdessen Folgendes schreiben:Es gibt eine weitere Option, die dem Benutzer eine flexiblere Benutzeroberfläche bietet:
Darüber hinaus können Sie die vorhandene vektorbasierte Schnittstelle unterstützen:
Dies ist möglicherweise weniger effizient als Ihr vorhandener Code, wenn Ihr vorhandener Code
reserve()
komplexer ist als nur ein fester Betrag im Voraus. Wenn Ihr vorhandener Codepush_back
den Vektor jedoch grundsätzlich wiederholt aufruft , sollte dieser vorlagenbasierte Code genauso gut sein.quelle
Es ist Zeit, dass ich eine Antwort über RVO poste , ich auch ...
Wenn Sie ein Objekt nach Wert zurückgeben, optimiert der Compiler dies häufig, damit es nicht zweimal erstellt wird, da es überflüssig ist, es in der Funktion als temporär zu erstellen und dann zu kopieren. Dies wird als Rückgabewertoptimierung bezeichnet: Das erstellte Objekt wird verschoben, anstatt kopiert zu werden.
quelle
Eine gängige Sprache vor C ++ 11 besteht darin, einen Verweis auf das zu füllende Objekt zu übergeben.
Dann erfolgt keine Kopie des Vektors.
quelle
Wenn der Compiler die Optimierung des benannten Rückgabewerts unterstützt ( http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx ), können Sie den Vektor direkt zurückgeben, sofern keine vorhanden ist:
NRVO optimiert die redundanten Kopierkonstruktor- und Destruktoraufrufe und verbessert somit die Gesamtleistung.
In Ihrem Beispiel sollte es keinen wirklichen Unterschied geben.
quelle
Und wenn Sie es auf main () drucken möchten, sollten Sie es in einer Schleife tun.
quelle
So schön "return by value" auch sein mag, es ist die Art von Code, die einen in einen Fehler führen kann. Betrachten Sie das folgende Programm:
Das obige fehlerhafte Programm zeigt keine Fehler an, selbst wenn man die GNU g ++ - Berichtsoptionen -Wall -Wextra -Weffc ++ verwendet
Wenn Sie einen Wert erzeugen müssen, funktioniert Folgendes, anstatt vecFunc () zweimal aufzurufen:
Das Obige erzeugt auch keine anonymen Objekte während der Iteration der Schleife, erfordert jedoch einen möglichen Kopiervorgang (der, wie einige Hinweise erwähnen, unter bestimmten Umständen wegoptimiert werden kann. Die Referenzmethode garantiert jedoch, dass keine Kopie erzeugt wird RVO ausführen ist kein Ersatz für den Versuch, den effizientesten Code zu erstellen, den Sie können. Wenn Sie die Notwendigkeit für den Compiler, RVO auszuführen, in Frage stellen können, sind Sie dem Spiel voraus.
quelle
quelle