Obwohl die vorhandene Antwort eine Problemumgehung mit std::move
bietet, die Ihr Programm kompiliert, muss gesagt werden, dass Ihre Verwendung von emplace_back
scheint auf einem Missverständnis beruhen.
Die Art und Weise Sie es beschreiben („Ich war zu versuchen, [...] Bewegen des Inhalts von einem Vektor zu einem anderen mit emplace_back()
“) und wie Sie es vorschlagen, verwenden, dass Sie von emplace_back
als Methode denken zu Verschieben Sie Elemente in den Vektor, und von push_back
als eine Methode zu kopieren Sie Elemente in einen Vektor.Der Code, den Sie die erste Instanz des Vektors verwenden zu füllen scheint dies auch vorschlagen:
std::vector<obj> v;
for(int i = 0; i < 1000; ++i)
{
v.emplace_back(obj("Jon"));
}
Aber das ist nicht das, was der Unterschied zwischen emplace_back
und push_back
geht.
Erstens wird selbst push_back
in den Vektor (nicht kopiert), um die Elemente zu bewegen, wenn es nur einen R-Wert gegeben wird, und wenn der Elementtyp einen Zug Zuweisungsoperator hat.
Zweitens die reale Anwendungsfall von emplace_back
ist Elemente zu konstruieren anstelle, das heißt Sie es verwenden, wenn Sie Objekte in einen Vektor möchten, die noch nicht vorhanden sind. Die Argumente von emplace_back
sind die Argumente für den Konstruktor des Objekts. So Ihre Schleife oben sollte wirklich so aussehen:
std::vector<obj> v;
for(int i = 0; i < 1000; ++i)
{
v.emplace_back("Jon"); // <-- just pass the string "Jon" , not obj("Jon")
}
Der Grund, warum Ihr vorhandener Code funktioniert ist, dass obj("Jon")
ist auch ein gültiges Argument für den Konstruktor (genauer gesagt, den Umzug Konstruktor). Aber die Grundidee von emplace_back
ist, dass Sie das Objekt nicht erstellen und dann verschieben müssen. Sie profitieren nicht von dieser Idee, wenn Sie statt "Jon"
zu ihm übergeben.
Auf der anderen Seite, in Ihrer zweiten Schleife beschäftigen Sie sich mit Objekten, die zuvor erstellt wurden. Es macht keinen Sinn, Objekte, die bereits existieren, mit emplace_back
zu verschieben. Und wieder, emplace_back
angewendet auf ein vorhandenes Objekt bedeutet nicht, dass das Objekt verschoben wird. Es bedeutet nur, dass es an Ort und Stelle mit dem gewöhnlichen Kopierkonstruktor erstellt wird (falls vorhanden). Wenn Sie möchten, um es zu bewegen, einfach push_back
verwenden, auf das Ergebnis der std::move
angewendet:
std::vector<obj> p;
for(int i = 0; i < 1000; ++i)
{
p.push_back(std::move(v[i])); // <-- Use push_back to move existing elements
}
Weitere Hinweise
1) Sie die Schleife vereinfachen kann C++ 11 oben mit bereichsbasierte für:
std::vector<obj> p;
for (auto &&obj : v)
p.push_back(std::move(obj));
2) Unabhängig davon, ob sie für eine gewöhnliche Steuerung oder bereichsbasierten Anwendungsgebiete bewegen Sie die eine Elemente nach dem anderen, was bedeutet, dass der Quellenvektor v
als ein Vektor von 1000 leer Objekte verbleiben. Wenn Sie tatsächlich den Vektor in dem Prozess löschen wollen (aber immer noch Semantik verwenden bewegt die Elemente auf den neuen Vektor zu transportieren), können Sie den Umzug Konstruktor des Vektors selbst verwenden:
std::vector<obj> p(std::move(v));
dies die zweite Schleife reduziert auf nur eine einzige Zeile, und es stellt sicher, dass der Quellvektor gelöscht wird.
Die Fehlermeldung besagt, dass 'obj' einen Kopierkonstruktor benötigt. – Mat
@mat warum muss es bauen? Es sollte nicht der Bewegungskonstruktor + der Bewegungszuweisungsoperator verwendet werden? – user1849534
Überprüfen Sie die Definition von [emplace_back] (http://en.cppreference.com/w/cpp/container/vector/emplace_back), Sie benötigen einen Konstruktor, der die übergebene 'emplace_back' übernimmt. Sie übergeben einen l-Wert und haben keinen übereinstimmenden Konstruktor. – Mat