Ich habe gehört, dass eine der Empfehlungen von Modern C ++ darin besteht, emplace_back
anstelle von push_back
zum Anhängen in Containern zu verwenden ( emplace_back
akzeptiert jede Version von Parametern eines Konstruktors der Speicher im Container eingeben).
Nach dem Standardentwurf N3797 23.3.6.5 (1) , sagen Sie:
Anmerkungen: Verursacht eine Neuzuweisung, wenn die neue Größe größer als die alte Kapazität ist. Wenn keine Neuzuweisung erfolgt, bleiben alle Iteratoren und Referenzen vor dem Einfügepunkt gültig. Wenn eine Ausnahme anders als durch den Kopierkonstruktor, den Konstruktor, den Zuweisungsoperator oder den Zuweisungsoperator von T oder durch eine beliebige InputIterator-Operation ausgelöst wird, gibt es keine Effekte. Wenn eine Ausnahme vom Verschiebungskonstruktor eines Nicht-CopyInsertable T ausgelöst wird, sind die Effekte nicht angegeben.
Dies gibt an, was passiert, wenn keine Neuzuweisung erforderlich ist, aber lassen Sie das Problem offen, wenn der Container wachsen muss.
In diesem Codeabschnitt:
%Vor%Kompiliert mit VC ++ (Visual Studio 2013 Update 4) und GCC 4.9.1 (MinGW) in Debug in Windows 8.1.
Bei der Kompilierung mit VC ++ lautet die Ausgabe:
%Vor%Bei der Übersetzung mit GCC lautet die Ausgabe:
%Vor% Überprüfung der Implementierung von emplace_back
in VC ++ Der Unterschied besteht darin, dass die ersten Zeilen des Codes prüfen, ob der Container wachsen muss (und wenn er benötigt wird), falls der Container wachsen soll, der Verweis auf Das erste Element ( buff [0] ), das in der Methode emplace_back
empfangen wurde, wird ungültig, und wenn die tatsächliche Einstellung des Werts im neu erstellten Element des Containers erfolgt, ist der Wert ungültig.
Im Fall von push_back
funktioniert, weil die Erstellung des anzuhängenden Elements in der Parameterbindung erfolgt (vor dem möglichen Wachstum des Containers).
Meine Frage ist:
Dieses Verhalten, wenn der Container wachsen muss, da ein Aufruf von emplace_back
und der Parameter eine Referenz auf den gleichen Container ist, ist die Implementierung definiert, unspezifiziert oder es gibt ein Problem bei der Implementierung eines Compilers (angenommen in VC ++ als GCC-Verhalten ist näher an der erwarteten)?
Wenn Sie den & amp; operator [] verwendet haben, der eine Referenz zurückgegeben hat. Sie haben dann emplace_back verwendet, was zu einer Neuzuweisung geführt und somit alle früheren Referenzen ungültig gemacht hat. Beide Regeln sind gut definiert. Das Richtige, was passieren sollte, ist eine Ausnahme. Ich erwarte tatsächlich, dass die VC ++ - Version eine Ausnahme auslöst, wenn Sie die Debug-Version unter dem Debugger ausführen.
push_back hat dieselben zwei Regeln, was bedeutet, dass es auch dasselbe tut. Ich bin mir fast sicher, dass das Umtauschen der beiden Zeilen emplace_back / push_back dasselbe Verhalten zur Folge hat.
Tags und Links c++ gcc c++11 visual-c++ stdvector