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 bietet explicit Konstruktoren mit einem Argument.
– joki
11. Juli 2017 um 19:10 Uhr
Verwandte: Gibt es einen Fall, wo push_back ist vorzuziehen emplace_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
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).
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::mapmü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.
Diese Klarstellung, dass es sich um ein MSVS10-Problem und nicht um ein C++-Problem handelt, ist hier der wichtigste Teil. Danke.
– ich22
21. Dezember 2010 um 5:49 Uhr
Ich glaube, Ihre letzte Zeile von C++-Code wird nicht funktionieren. pair<const int,Complicated> hat keinen Konstruktor, der ein int, ein weiteres int, ein double und als 4. Parameter einen String akzeptiert. Aber du kann Konstruieren Sie dieses Paarobjekt direkt mit seinem stückweisen Konstruktor. Die Syntax wird natürlich anders sein: m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
– Sellibitze
14. März 2013 um 15:08 Uhr
Glücklicherweise werden unterschiedliche Vorlagen in VS2013 enthalten sein, jetzt in der Vorschau.
– Daniel Earwicker
25. Juli 2013 um 20:37 Uhr
Sollte diese Antwort aktualisiert werden, um die neuen Entwicklungen in vs2013 widerzuspiegeln?
– wink
27. Februar 2014 um 16:20 Uhr
Wenn Sie Visual Studio 2013 oder höher verwenden jetztSie sollten Unterstützung für das “Echte” haben emplace_back solange es in Visual C++ implementiert wurde, als variadische Vorlagen hinzugefügt wurden: msdn.microsoft.com/en-us/library/hh567368.aspx
– kayleeFrye_onDeck
28. Juni 2017 um 20:17 Uhr
Besucher
emplace_back sollte kein Argument vom Typ annehmen vector::value_typesondern stattdessen variadische Argumente, die an den Konstruktor des angehängten Elements weitergeleitet werden.
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.
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
@David: aber dann bist du umgezogen s im Umfang, ist das nicht gefährlich?
– Matthias M.
29. November 2010 um 17:56 Uhr
Es ist nicht gefährlich, wenn Sie s wegen seines Wertes nicht mehr verwenden möchten. Das Verschieben macht s nicht ungültig, das Verschieben stiehlt nur die bereits in s vorgenommene interne Speicherzuweisung und belässt es in einem Standardzustand (kein Stich zugewiesen), der nach der Zerstörung in Ordnung ist, als hätten Sie gerade std::string str;
– David
30. November 2010 um 0:52 Uhr
@David: Ich bin mir nicht sicher, ob ein verschobenes Objekt für jede Verwendung außer der anschließenden Zerstörung gültig sein muss.
– Ben Voigt
12. Dezember 2010 um 1:31 Uhr
vec.emplace_back("Hello") wird funktionieren, da die const char* Argument wird sein weitergeleitet zum string Konstrukteur. Das ist der springende Punkt emplace_back.
– Alexander C.
9. August 2011 um 20:28 Uhr
@BenVoigt: Ein verschobenes Objekt muss sich in einem gültigen (aber nicht spezifizierten) Zustand befinden. Dies bedeutet jedoch nicht unbedingt, dass Sie jede Operation daran ausführen können. Erwägen std::vector. Ein leeres std::vector ist ein gültiger Zustand, aber Sie können nicht anrufen front() darauf. Das bedeutet, dass jede Funktion, die keine Vorbedingungen hat, trotzdem aufgerufen werden kann (und Destruktoren niemals Vorbedingungen haben können).
– David Stein
10. Mai 2012 um 4:06 Uhr
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_backA (int x_arg) heißt zuerst und move A (A &&rhs) wird danach aufgerufen.
Der Konstruktor muss natürlich als gekennzeichnet sein explicitaber 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 &&)
Ich kam hierher, nachdem ich bemerkt hatte, dass ich Code hatte, der anrief v.emplace_back(x); wobei x explizit bewegungskonstruierbar, aber nur explizit kopierkonstruierbar ist. Die Tatsache, dass emplace_back “implizit” explizit ist, lässt mich denken, dass meine Go-to-Funktion zum Anhängen wahrscheinlich sein sollte push_back. Gedanken?
– Ben
25. Oktober 2019 um 19:19 Uhr
Wenn Sie anrufen a.emplace_back Beim zweiten Mal wird der Move-Konstruktor aufgerufen!
–AndreasK.
21. Mai 2020 um 15:18 Uhr
@AndreasK. Das hängt nicht mit emplace_back zusammen, sondern erweitert die Größe des Vektors. Sie können dies überprüfen, indem Sie drucken, was verschoben wird, anstatt nur "A (A &&)\n"drucken "A (A &&) on " << rhs.x << "\n". Du kannst es sehen in diesem bearbeiteten Codeausschnitt.
– Brambor
25. August 2021 um 22:09 Uhr
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.
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_typeKonstruktor, 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_backwenn 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 vectorwas 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