Ich bin etwas verwirrt über den Unterschied zwischen 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
Überlastung gibt, die eine R-Wert-Referenz nimmt, sehe ich nicht ganz, wozu der Zweck emplace_back
wird?
template <class _Valty> void emplace_back(_Valty&& _Val)
Version gibt, die eine universelle Referenz verwendet, die eine perfekte Weiterleitung anexplicit
Konstruktoren mit einzelnen Argumenten ermöglicht.push_back
vorzuziehen istemplace_back
? Der einzige Fall, an den ich denken kann, ist, wenn eine Klasse irgendwie kopierbar (T&operator=(constT&)
), aber nicht konstruierbar (T(constT&)
) wäre, aber ich kann mir nicht vorstellen, warum man das jemals wollen würde.Antworten:
Zusätzlich zu dem, was der Besucher sagte:
Die
void emplace_back(Type&& _Val)
von MSCV10 bereitgestellte Funktion ist nicht konform und redundant, da sie, wie Sie bemerkt haben, streng gleichwertig ist mitpush_back(Type&& _Val)
.Aber die echte C ++ 0x-Form von
emplace_back
ist wirklich nützlich :void emplace_back(Args&&...)
;Anstatt a zu nehmen
value_type
, wird eine variable Liste von Argumenten verwendet, was bedeutet, dass Sie die Argumente jetzt perfekt weiterleiten und ein Objekt direkt in einen Container ohne temporäre Elemente konstruieren können.Das ist nützlich, denn egal wie viel Klugheit RVO und Bewegungssemantik auf den Tisch bringen, es gibt immer noch komplizierte Fälle, in denen ein push_back wahrscheinlich unnötige Kopien (oder Verschiebungen) erstellt. Zum Beispiel müssen Sie mit der traditionellen
insert()
Funktion von astd::map
eine temporäre Funktion erstellen, die dann in a kopiertstd::pair<Key, Value>
wird und dann in die Karte kopiert wird:Warum haben sie nicht die richtige Version von emplace_back in MSVC implementiert? Eigentlich hat es mich vor einiger Zeit auch nervt, also habe ich die gleiche Frage im Visual C ++ - Blog gestellt . Hier ist die Antwort von Stephan T Lavavej, dem offiziellen Betreuer der Implementierung der Visual C ++ - Standardbibliothek bei Microsoft.
Es ist eine verständliche Entscheidung. Jeder, der nur einmal versucht hat, eine variable Vorlage mit schrecklichen Tricks des Präprozessors zu emulieren, weiß, wie ekelhaft dieses Zeug wird.
quelle
pair<const int,Complicated>
hat keinen Konstruktor, der ein int, ein anderes int, ein double und als 4. Parameter einen String nimmt. Sie können dieses Paarobjekt jedoch direkt mit seinem stückweisen Konstruktor erstellen. Die Syntax wird natürlich anders sein:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
emplace_back
so lange es in Visual C ++ implementiert wurde , wenn variadische Vorlagen hinzugefügt wurden: msdn.microsoft.com/en-us/library/hh567368. aspxemplace_back
sollte kein Argument vom Typvector::value_type
annehmen, sondern verschiedene Argumente, die an den Konstruktor des angehängten Elements weitergeleitet werden.Es ist möglich, eine zu übergeben,
value_type
die an den Kopierkonstruktor weitergeleitet wird.Da die Argumente weitergeleitet werden, bedeutet dies, dass der Container eine "kopierte" Kopie und keine verschobene Kopie speichert, wenn Sie keinen r-Wert haben.
Aber das Obige sollte identisch sein mit dem, was
push_back
tut. Es ist wahrscheinlich eher für Anwendungsfälle gedacht wie:quelle
s
, ist das nicht gefährlich?vec.emplace_back("Hello")
funktionieren wird, da dasconst char*
wird Argument werden weitergeleitet an denstring
Konstruktor. Das ist der springende Punkt vonemplace_back
.std::vector
. Ein Leerzeichenstd::vector
ist ein gültiger Status, den Sie jedoch nicht aufrufenfront()
können. Dies bedeutet, dass jede Funktion, die keine Vorbedingungen hat, weiterhin aufgerufen werden kann (und Destruktoren können niemals Vorbedingungen haben).Die Optimierung für
emplace_back
kann im nächsten Beispiel demonstriert werden.Für
emplace_back
KonstruktorA (int x_arg)
wird aufgerufen. Und dennpush_back
A (int x_arg)
heißt zuerst undmove A (A &&rhs)
wird danach gerufen.Natürlich muss der Konstruktor als markiert werden
explicit
, aber für das aktuelle Beispiel ist es gut, explizite Aussagen zu entfernen.Ausgabe:
quelle
emplace_back
vs tatsächlich passiertpush_back
.v.emplace_back(x);
wobei x explizit verschiebbar, aber nur explizit kopierbar ist. Die Tatsache, dassemplace_back
"implizit" explizit ist, lässt mich denken, dass meine Go-to-Funktion zum Anhängen wahrscheinlich sein solltepush_back
. Gedanken?a.emplace_back
zweite Mal aufrufen , wird der Verschiebungskonstruktor aufgerufen!Ein netter Code für push_back und emplace_back wird hier gezeigt.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
Sie können den Verschiebevorgang auf push_back und nicht auf emplace_back sehen.
quelle
emplace_back
Eine konforme Implementierung leitet Argumente an denvector<Object>::value_type
Konstruktor weiter, wenn sie dem Vektor hinzugefügt werden. Ich erinnere mich, dass Visual Studio keine variadic-Vorlagen unterstützt hat, aber mit variadic-Vorlagen in Visual Studio 2013 RC unterstützt wird, wird vermutlich eine konforme Signatur hinzugefügt.Mit
emplace_back
, wenn Sie die Argumente direkt weiterleitenvector<Object>::value_type
Konstruktor, nicht wahr eine Art benötigt für bewegliche oder kopierbar seineemplace_back
Funktion, genau genommen. In diesemvector<NonCopyableNonMovableObject>
Fall ist dies nicht sinnvoll, davector<Object>::value_type
zum Wachsen ein kopierbarer oder beweglicher Typ erforderlich ist.Aber zur Kenntnis , dass dies für sinnvoll sein könnte
std::map<Key, NonCopyableNonMovableObject>
, da , wenn Sie einen Eintrag in der Karte zuzuordnen, ist es nicht bewegt werden muß oder überhaupt nicht mehr kopiert werden , im Gegensatz zuvector
, was bedeutet , dass Sie verwenden können ,std::map
effektiv mit einem zugeordneten Typ, der weder kopierbar ist noch beweglich.quelle
Noch eine bei Listen:
quelle
Spezifischer Anwendungsfall für
emplace_back
: Wenn Sie ein temporäres Objekt erstellen müssen, das dann in einen Container verschoben wird, verwenden Sieemplace_back
anstelle vonpush_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 füremplace_back
die verwendet wird, ist jedoch leistungsfähiger als das Konstruieren und anschließende Verschieben des Objekts (was im Allgemeinen ein Kopieren erfordert).emplace_back
stattpush_back
in allen Fällen ohne große Probleme verwenden. (Siehe Ausnahmen )quelle