Was ist der Unterschied zwischen default copy und std::move in diesem Beispiel?
Nach dem move das Objekt gibt es eine Abhängigkeit zwischen neuen und alten?
int main () {
int a = 100;
std::cout<<&a<<std::endl;
auto a_copy = a; // deduced as int
std::cout<<&a_copy<<std::endl;
auto a_move = std::move(a); // deduced as int
std::cout<<&a_move<<std::endl;
};
Ausgang:
0x7fffffffe094
0x7fffffffe098
0x7fffffffe09c
Beachten Sie, dass std::move bewegt eigentlich nichts. Es führt nur eine Umwandlung in rvalue ref durch, und das Ergebnis ist hilfreicherweise ein rvalue, während es einfach benannt wird a ist nicht. Diese beiden Tatsachen sind Teil der Bereitstellung eines Objekts, von dem aus man sich bewegt, aber sie sind nicht wirklich das Ding, das sich von ihm wegbewegt. Die Frage nach „nachher move” ist ein Ablenkungsmanöver.
– Leichtigkeitsrennen im Orbit
11. Januar 2015 um 15:56 Uhr
Barry
Im Das Beispiel, es gibt keinen Unterschied. Wir werden mit 3 enden ints mit dem Wert 100. Es kann jedoch definitiv einen Unterschied zwischen verschiedenen Typen geben. Betrachten wir zum Beispiel etwas wie vector<int>:
std::vector<int> a = {1, 2, 3, 4, 5}; // a has size 5
auto a_copy = a; // copy a. now we have two vectors of size 5
auto a_move = std::move(a); // *move* a into a_move
Die letzte Variable, a_moveübernimmt das Eigentum adie internen Zeiger von . Was wir also am Ende haben, ist a_move ist ein Vektor der Größe 5, aber a ist jetzt leer. Die move ist viel effizienter als a copy (Stellen Sie sich vor, es wäre stattdessen ein Vektor aus 1000 Zeichenfolgen – a_copy würde beinhalten, einen 1000-String-Puffer zuzuweisen und 1000 Strings zu kopieren, aber a_move weist nur ein paar Hinweise zu).
Für einige andere Typen könnte einer ungültig sein:
std::unique_ptr<int> a{new int 42};
auto a_copy = a; // error
auto a_move = std::move(a); // OK, now a_move owns 42, but a points to nothing
Für viele Typen gibt es jedoch keinen Unterschied:
std::array<int, 100> a;
auto a_copy = a; // copy 100 ints
auto a_move = std::move(a); // also copy 100 ints, no special move ctor
Allgemeiner:
T a;
auto a_copy = a; // calls T(const T& ), the copy constructor
auto a_move = std::move(a); // calls T(T&& ), the move constructor
@Person.Junkie Ja, std::move führt nur eine statische Umwandlung in rvalue ref durch, bevorzugt es aber definitiv std::move() Überschreiben der Besetzung – es ist (a) weniger Tippen und (b) macht die Absicht der Codezeile viel klarer.
– Barri
11. Januar 2015 um 15:58 Uhr
@Barry: Ich bin anderer Meinung – obwohl es viel kürzer ist, ist es a Lüge.
– Leichtigkeitsrennen im Orbit
11. Januar 2015 um 15:59 Uhr
@LightnessRacesinOrbit würdest du lieber sehen std::move umbenannt in etwas wie std::rref? Weil ich weiß, ich würde – std::move ist extrem irreführend.
– mbgda
11. Januar 2015 um 16:38 Uhr
@Barry: Ja, los geht’s; das ist wahrscheinlich das, woran ich mich erinnere. Ich glaube, es ist ein Punkt, der ein paar Mal von verschiedenen hochkarätigen Typen eingeräumt wurde (im Gegensatz zu der Beschränkung auf Forenbeiträge auf cprogramming.com). Das heißt, „es bedeutet Absicht“ ist ein nettes Prinzip, das in einfachen Skriptsprachen gut funktionieren mag, aber in etwas so Flexiblem wie C++ der Logik (ganz zu schweigen von etablierten Paradigmen) völlig widerspricht.
– Leichtigkeitsrennen im Orbit
11. Januar 2015 um 16:45 Uhr
Der Vektor a ist nach dem Umzug nicht garantiert leer.
– TC
11. Januar 2015 um 20:38 Uhr
Verwenden std::move ändert nur einen lvalue in einen xvalue, sodass es für die Verwendung mit Move-Konstruktoren und Move-Zuweisungsoperatoren geeignet ist. Diese sind für eingebaute Typen nicht vorhanden, daher macht die Verwendung von move in diesem Beispiel keinen Unterschied.
Juanchopanza
Was ist der Unterschied zwischen default copy und std::move in diesem Beispiel?
Es gibt keinen Unterschied. Das Kopieren von etwas erfüllt die Anforderungen einer Verschiebung, und im Fall von eingebauten Typen wird die Verschiebung als Kopie implementiert.
Nach dem Verschieben des Objekts besteht eine Abhängigkeit zwischen neu und alt
Nein, es gibt keine Abhängigkeiten. Beide Variablen sind unabhängig.
…und was ist der Vorteil von std::move und warum?
– Person.Junkie
11. Januar 2015 um 15:45 Uhr
@Person.Junkie Hier? Es gibt keinen Vorteil. Der Nachteil ist, dass der Code unübersichtlich ist.
– Juanchopanza
11. Januar 2015 um 15:46 Uhr
Im Allgemeinen? Warum gibt es std::move? Ich weiß, dass std::move lvalue/rvalue mithilfe von static_cast in rvalue konvertiert. Kann diese „Umwandlung“ eine große Verbesserung bewirken?
– Person.Junkie
11. Januar 2015 um 15:49 Uhr
@Person.Junkie Das ist viel zu weit gefasst. Darüber gibt es ganze Abhandlungen. Aber im Grunde sind einige Typen billig zu bewegen und teuer zu kopieren. In diesen Fällen kann ein Umzug von Vorteil sein. Außerdem sind einige Dinge nicht kopierbar, können aber verschoben werden (z. B. ein Dateistream oder ein eindeutiger Zeiger).
– Juanchopanza
11. Januar 2015 um 15:50 Uhr
@Person.Junkie: Die Besetzung selbst bewirkt keine “große Verbesserung”. Die Besetzung ermöglicht es einem Programmierer bequem anzugeben, dass er a möchte unterschiedlich Funktion, die aufgerufen wird, um die Datenübertragung zu implementieren: Herkömmlicherweise schreiben wir “Bewegungskonstruktoren”, die eher bewegen als kopieren, z. B. durch Vertauschen interner Zeiger. Das kann ein verursachen enorm Verbesserung, aber std::move selbst tut das nicht. Sie könnten es in C++03 mit Tags und verschiedenen anderen Techniken machen, es war nur nicht ganz so bequem (und konnte nicht generisch funktionieren, z. B. Elemente in Standardbibliothekscontainern).
– Leichtigkeitsrennen im Orbit
11. Januar 2015 um 15:58 Uhr
mbgda
Um die Antwort des anderen Posters zu erweitern, gilt das Move-is-a-Copy-Paradigma auch für alle Datenstrukturen, die aus POD-Typen bestehen (oder aus anderen Typen bestehen, die aus POD-Typen bestehen), wie in diesem Beispiel:
struct Foo
{
int values[100];
bool flagA;
bool flagB;
};
struct Bar
{
Foo foo1;
Foo foo2;
};
int main()
{
Foo f;
Foo fCopy = std::move(f);
Bar b;
Bar bCopy = std::move(b);
return 0;
}
Bei beiden Foo und Bar Es gibt keine sinnvolle Möglichkeit, die Daten von einem zum anderen zu verschieben, da beide letztendlich Aggregate von POD-Typen sind – keine ihrer Daten gehört indirekt (zeigt auf oder verweist auf anderen Speicher). In diesen Fällen wird der Umzug also als Kopie und Originale (f, b) bleiben nach den Zuordnungen auf der unverändert std::move() Linien.
Bewegungssemantik kann nur mit dynamisch zugewiesenem Speicher oder eindeutigen Ressourcen sinnvoll implementiert werden.
Beachten Sie, dass
std::move
bewegt eigentlich nichts. Es führt nur eine Umwandlung in rvalue ref durch, und das Ergebnis ist hilfreicherweise ein rvalue, während es einfach benannt wirda
ist nicht. Diese beiden Tatsachen sind Teil der Bereitstellung eines Objekts, von dem aus man sich bewegt, aber sie sind nicht wirklich das Ding, das sich von ihm wegbewegt. Die Frage nach „nachhermove
” ist ein Ablenkungsmanöver.– Leichtigkeitsrennen im Orbit
11. Januar 2015 um 15:56 Uhr