Effizienz von C ++ 11 push_back () mit std :: move versus emplace_back () für bereits erstellte Objekte


83

In C ++ 11 emplace_back()ist im allgemeinen bevorzugt (in Bezug auf der Effizienz) zu , push_back()da es ermöglicht , in-Place - Konstruktion, aber das ist immer noch der Fall , bei der Verwendung push_back(std::move())mit einem bereits aufgebauten Objekt?

Wird zum Beispiel emplace_back()in Fällen wie den folgenden immer noch bevorzugt?

std::string mystring("hello world");
std::vector<std::string> myvector;

myvector.emplace_back(mystring);
myvector.push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)

Gibt es im obigen Beispiel außerdem einen Vorteil, wenn Sie stattdessen Folgendes tun:

myvector.emplace_back(std::move(mystring));

oder ist der Umzug hierher völlig überflüssig oder hat er keine Auswirkungen?


myvector.emplace_back(mystring);kopiert und bewegt sich nicht. Die anderen beiden Züge sollten gleich sein.
— TC

Antworten:


114

Mal sehen, was die verschiedenen von Ihnen bereitgestellten Anrufe bewirken:

  1. emplace_back(mystring): Dies ist eine direkte Konstruktion des neuen Elements mit dem von Ihnen angegebenen Argument. Da Sie einen Wert angegeben haben, handelt es sich bei dieser In-Place-Konstruktion tatsächlich um eine Kopierkonstruktion, dh dies entspricht dem Aufrufenpush_back(mystring)

  2. push_back(std::move(mystring)): Dies ruft die Verschiebungseinfügung auf, die im Fall von std :: string eine direkte Verschiebungskonstruktion ist.

  3. emplace_back(std::move(mystring)): Dies ist wieder eine In-Place-Konstruktion mit den von Ihnen angegebenen Argumenten. Da dieses Argument ein r-Wert ist, nennt es den Verschiebungskonstruktor von std::string, dh es ist eine direkte Verschiebungskonstruktion wie in 2.

Mit anderen Worten, wenn es mit einem Argument vom Typ T aufgerufen wird, sei es ein r-Wert oder ein l-Wert emplace_backund push_backsind äquivalent.

Für alle anderen Argumente emplace_backgewinnt das Rennen jedoch, zum Beispiel mit einem char const*in a vector<string>:

  1. emplace_back("foo")fordert string::string(char const*)eine In-Place-Konstruktion.

  2. push_back("foo")Zuerst muss string::string(char const*)die implizite Konvertierung aufgerufen werden, die erforderlich ist, um mit der Signatur der Funktion übereinzustimmen, und dann eine Einfügung wie in Fall 2 oben. Daher ist es gleichbedeutend mitpush_back(string("foo"))


1
Der Verschiebungskonstruktor ist im Allgemeinen effizienter als die Kopierkonstruktoren, daher ist die Verwendung von rvalue (Fall 2, 3) trotz derselben Semantik effizienter als die Verwendung eines lvalue (Fall 1).
— Ryan Li

Was ist mit einer solchen Situation? void foo (string && s) {vector.emplace (s); // 1 vector.emplace (std :: move (s)); // 2}
— VALOD9

@VALOD das sind wieder die Nummern 1 und 3 meiner Liste. skann nur rvalues daß bindet , wie rvalue Referenz definiert werden, aber innerhalb von foo, sist ein L - Wert.
— Arne Mertz

1

Der emplace_back ruft eine Liste von rvalue-Referenzen ab und versucht, ein Containerelement direkt an Ort und Stelle zu erstellen. Sie können emplace_back mit allen Typen aufrufen, die von den Containerelementkonstruktoren unterstützt werden. Wenn Sie emplace_back für Parameter aufrufen, die keine rvalue-Referenzen sind, wird auf normale Referenzen zurückgegriffen, und zumindest der Kopierkonstruktor wird aufgerufen, wenn der Parameter und die Containerelemente vom gleichen Typ sind. In Ihrem Fall sollte 'myvector.emplace_back (mystring)' eine Kopie der Zeichenfolge erstellen, da der Compiler nicht wissen konnte, dass der Parameter myvector beweglich ist. Fügen Sie also std :: move ein, um den gewünschten Nutzen zu erzielen. Der push_back sollte für bereits erstellte Elemente genauso funktionieren wie emplace_back.


2
Das ist eine ... interessante Art, Weiterleitungen / universelle Referenzen zu beschreiben.
— TC
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.