Kann ich ein gültiges C ++ 03 Programm brechen, indem ich std::vector::push_back
durch emplace_back
ersetze und es mit dem C ++ 11 Compiler kompiliere? Aus dem Lesen von emplace_back
Verweis Ich nehme an, es sollte nicht passieren, aber ich gebe zu, ich bekomme nicht vollständig rvalue Referenzen.
Ich habe ein kurzes Beispiel erstellt, das nicht kompiliert werden kann, wenn push_back
durch emplace_back
ersetzt wird:
Der Aufruf von push_back
muss sein Argument 0
vom Typ int
in den Typ S
konvertieren. Da es sich um eine implizite Konvertierung handelt, wird der explizite Konstruktor S::S(int)
nicht berücksichtigt und S::S(double)
wird aufgerufen. Auf der anderen Seite führt emplace_back
eine direkte Initialisierung durch, so dass sowohl S::S(double)
als auch S::S(int)
berücksichtigt werden. Letzteres ist eine bessere Übereinstimmung, aber es ist private
, so dass das Programm schlecht gebildet ist.
Ja, Sie können das Verhalten ändern (mehr als nur das Vermeiden eines Kopierkonstruktoraufrufs), da emplace_back
nur unvollständig weitergeleitete Argumente sieht.
Beispiel erstellt:
%Vor% Addendum : Wie Brian Bi in seine Antwort betont, kann dies ein weiterer Unterschied sein führen zu einem anderen Verhalten ist, dass ein push_back
Aufruf beinhaltet eine implizite Konvertierung in T
, die explicit
Konstruktoren und Konvertierungsoperatoren ignoriert, während emplace_back
direkte Initialisierung verwendet, die auch explicit
Konstruktoren und Konvertierungsoperatoren berücksichtigt.
Die emplace
-Versionen erzeugen ausnahmsweise kein Objekt des gewünschten Typs . Dies kann zu einem Fehler führen.
Betrachten Sie das folgende Beispiel, das zur Vereinfachung einfach std::vector
verwendet (angenommen uptr
verhält sich wie std::unique_ptr
, außer dass der Konstruktor nicht explizit ist):
Es ist ausnahmesicher. Ein temporäres uptr<T>
wird erstellt, um an push_back
zu übergeben, das in den Vektor verschoben wird. Wenn die Neuzuweisung des Vektors fehlschlägt, gehört das zugewiesene T
noch immer einem intelligenten Zeiger, der es korrekt löscht.
Vergleiche mit:
%Vor% emplace_back
darf kein temporäres Objekt erstellen. Der ptr
wird einmalig im Vektor erstellt. Wenn die Neuzuweisung fehlschlägt, gibt es keinen Speicherort für die direkte Erstellung, und es wird nie ein intelligenter Zeiger erstellt. Der T
wird geleakt.
Die beste Alternative ist natürlich:
%Vor%entspricht dem ersten, macht aber die Erstellung des intelligenten Zeigers explizit.