Gibt es Fälle, in denen es falsch ist, push_back durch emplace_back zu ersetzen?

8

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.

    
Violet Giraffe 27.02.2014, 21:02
quelle

4 Antworten

14

Ich habe ein kurzes Beispiel erstellt, das nicht kompiliert werden kann, wenn push_back durch emplace_back ersetzt wird:

%Vor%

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.

    
Brian 27.02.2014, 23:45
quelle
2

Ja, Sie können das Verhalten ändern (mehr als nur das Vermeiden eines Kopierkonstruktoraufrufs), da emplace_back nur unvollständig weitergeleitete Argumente sieht.

%Vor%

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.

    
Cheers and hth. - Alf 27.02.2014 22:46
quelle
1

Wenn Sie im Kopierkonstruktor der Objekte, die Sie in Ihrem Vektor haben, keine verrückten Nebenwirkungen haben, dann nein.

emplace_back wurde eingeführt, um unnötiges Kopieren und Verschieben zu optimieren.

    
Kissiel 27.02.2014 21:08
quelle
1

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):

%Vor%

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.

    
Ben Voigt 20.07.2014 02:59
quelle

Tags und Links