
Ronag
Ich bin etwas verwirrt, was den Unterschied zwischen angeht push_back
und emplace_back
.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Da es eine push_back
Überladung mit einer Rvalue-Referenz Ich verstehe nicht ganz, was der Zweck ist emplace_back
wird?

Thomas Petit
Zusätzlich zu dem, was der Besucher gesagt hat:
Die Funktion void emplace_back(Type&& _Val)
bereitgestellt von MSCV10 ist nicht konform und redundant, da es, wie Sie angemerkt haben, absolut gleichwertig ist push_back(Type&& _Val)
.
Aber die echte C++0x-Form von emplace_back
ist wirklich praktisch: void emplace_back(Args&&...)
;
Anstatt eine zu nehmen value_type
es braucht eine variadische Liste von Argumenten, was bedeutet, dass Sie jetzt die Argumente perfekt weiterleiten und direkt ein Objekt in einen Container konstruieren können, ohne überhaupt ein Temporär.
Das ist nützlich, denn egal wie viel Cleverness RVO und Move-Semantik auf den Tisch bringen, es gibt immer noch komplizierte Fälle, in denen ein Push_back wahrscheinlich unnötige Kopien (oder Moves) anfertigt. Zum Beispiel mit dem Traditionellen insert()
Funktion von a std::map
müssen Sie eine temporäre erstellen, die dann in eine kopiert wird std::pair<Key, Value>
die dann in die Karte kopiert werden:
std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";
// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));
// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);
Warum haben sie also nicht die richtige Version von emplace_back in MSVC implementiert? Eigentlich hat es mich vor einer Weile auch genervt, also habe ich die gleiche Frage zum Thema gestellt Visual C++-Blog. Hier ist die Antwort von Stephan T. Lavavej, dem offiziellen Betreuer der Visual C++-Standardbibliotheksimplementierung bei Microsoft.
F: Sind Beta-2-emplace-Funktionen derzeit nur eine Art Platzhalter?
A: Wie Sie vielleicht wissen, sind variadische Vorlagen nicht in VC10 implementiert. Wir simulieren sie mit Präprozessormaschinen für Dinge wie
make_shared<T>()
Tupel und die neuen Dinge in <functional>
. Diese Vorverarbeitungsmaschinerie ist relativ schwierig zu verwenden und zu warten. Außerdem wirkt sich dies erheblich auf die Kompilierungsgeschwindigkeit aus, da wir wiederholt Unterüberschriften einfügen müssen. Aufgrund einer Kombination aus Zeitbeschränkungen und Bedenken hinsichtlich der Kompilierungsgeschwindigkeit haben wir keine variadischen Vorlagen in unseren Emplace-Funktionen simuliert.
Wenn verschiedene Vorlagen im Compiler implementiert sind, können Sie davon ausgehen, dass wir sie in den Bibliotheken nutzen, einschließlich in unseren emplace-Funktionen. Wir nehmen Konformität sehr ernst, können aber leider nicht alles auf einmal erledigen.
Es ist eine nachvollziehbare Entscheidung. Jeder, der nur einmal versucht hat, Variadic-Templates mit Präprozessor-Schreckenstricks zu emulieren, weiß, wie ekelhaft dieses Zeug wird.

Besucher
emplace_back
sollte kein Argument vom Typ annehmen vector::value_type
sondern stattdessen variadische Argumente, die an den Konstruktor des angehängten Elements weitergeleitet werden.
template <class... Args> void emplace_back(Args&&... args);
Es ist möglich, a zu bestehen value_type
die an den Kopierkonstruktor weitergeleitet werden.
Da die Argumente weitergeleitet werden, bedeutet dies, dass, wenn Sie keinen rvalue haben, dies immer noch bedeutet, dass der Container eine “kopierte” Kopie speichert, keine verschobene Kopie.
std::vector<std::string> vec;
vec.emplace_back(std::string("Hello")); // moves
std::string s;
vec.emplace_back(s); //copies
Aber das obige sollte identisch mit dem sein, was push_back
tut. Es ist wahrscheinlich eher für Anwendungsfälle gedacht wie:
std::vector<std::pair<std::string, std::string> > vec;
vec.emplace_back(std::string("Hello"), std::string("world"));
// should end up invoking this constructor:
//template<class U, class V> pair(U&& x, V&& y);
//without making any copies of the strings

vadikrobot
Optimierung für emplace_back
kann im nächsten Beispiel demonstriert werden.
Zum emplace_back
Konstrukteur A (int x_arg)
wird angerufen werden. Und für
push_back
A (int x_arg)
heißt zuerst und move A (A &&rhs)
wird danach aufgerufen.
Der Konstruktor muss natürlich als gekennzeichnet sein explicit
aber für das aktuelle Beispiel ist es gut, die Explizitheit zu entfernen.
#include <iostream>
#include <vector>
class A
{
public:
A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
A () { x = 0; std::cout << "A ()\n"; }
A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }
private:
int x;
};
int main ()
{
{
std::vector<A> a;
std::cout << "call emplace_back:\n";
a.emplace_back (0);
}
{
std::vector<A> a;
std::cout << "call push_back:\n";
a.push_back (1);
}
return 0;
}
Ausgang:
call emplace_back:
A (x_arg)
call push_back:
A (x_arg)
A (A &&)
Noch ein Beispiel für Listen:
// constructs the elements in place.
emplace_back("element");
// creates a new object and then copies (or moves) that object.
push_back(ExplicitDataType{"element"});

vaibhav kumar
Spezifischer Anwendungsfall für emplace_back
: Wenn Sie ein temporäres Objekt erstellen müssen, das dann in einen Container verschoben wird, verwenden Sie emplace_back
anstatt push_back
. Das Objekt wird direkt im Container erstellt.
Anmerkungen:
push_back
im obigen Fall wird ein temporäres Objekt erstellt und in den Container verschoben. In-Place-Konstruktion verwendet jedoch für emplace_back
wäre performanter, als das Objekt zu konstruieren und dann zu verschieben (was im Allgemeinen etwas Kopieren erfordert).
- Im Allgemeinen können Sie verwenden
emplace_back
anstatt push_back
in allen Fällen ohne große Probleme. (Siehe Ausnahmen)

Dharma
Ein schöner Code für push_back und emplace_back wird hier gezeigt.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
Sie können die Verschiebungsoperation auf push_back und nicht auf emplace_back sehen.
emplace_back
konforme Implementierung wird Argumente an die weiterleiten vector<Object>::value_type
Konstruktor, wenn er dem Vektor hinzugefügt wird. Ich erinnere mich, dass Visual Studio keine Variadic-Vorlagen unterstützt hat, aber mit Variadic-Vorlagen werden in Visual Studio 2013 RC unterstützt, also denke ich, dass eine konforme Signatur hinzugefügt wird.
Mit emplace_back
wenn Sie die Argumente direkt an weiterleiten vector<Object>::value_type
Konstruktor benötigen Sie keinen Typ, der verschiebbar oder kopierbar ist emplace_back
Funktion, genau genommen. In dem vector<NonCopyableNonMovableObject>
Fall ist dies nicht sinnvoll, da vector<Object>::value_type
benötigt einen kopierbaren oder verschiebbaren Typ, um zu wachsen.
Aber Hinweis dass dies nützlich sein könnte std::map<Key, NonCopyableNonMovableObject>
denn sobald Sie einen Eintrag in der Karte zugewiesen haben, muss dieser nicht mehr verschoben oder kopiert werden, im Gegensatz zu mit vector
was bedeutet, dass Sie verwenden können std::map
effektiv mit einem zugeordneten Typ, der weder kopierbar noch verschiebbar ist.
9963200cookie-checkpush_back gegen emplace_backyes
Gute Lektüre hier: open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2642.pdf
– Johann Kotlinski
29. November 2010 um 14:00 Uhr
Beachten Sie, dass (wie Thomas unten sagt) der Code in der Frage von MSVS stammt Emulation von C++0x, nicht was C++0x eigentlich ist.
– ich22
21. Dezember 2010 um 5:50 Uhr
Ein besser zu lesender Artikel wäre: open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2345.pdf. N2642 ist hauptsächlich eine Formulierung für den Standard; N2345 ist das Papier, das die Idee erklärt und motiviert.
– Alan
13. März 2013 um 23:10 Uhr
Beachten Sie, dass es sogar in MSVC10 eine
template <class _Valty> void emplace_back(_Valty&& _Val)
Version, die eine dauert universelle Referenz die perfekte Weiterleitung an bietetexplicit
Konstruktoren mit einem Argument.– joki
11. Juli 2017 um 19:10 Uhr
Verwandte: Gibt es einen Fall, wo
push_back
ist vorzuziehenemplace_back
? Der einzige Fall, an den ich denken kann, ist, wenn eine Klasse irgendwie kopierbar wäre (T&operator=(constT&)
) aber nicht konstruierbar (T(constT&)
), aber ich kann mir nicht vorstellen, warum man das jemals wollen sollte.– Ben
25. Mai 2018 um 18:44 Uhr