Die C ++ 11- std::move(x)
Funktion bewegt überhaupt nichts. Es ist nur eine Besetzung auf r-Wert. Warum wurde das gemacht? Ist das nicht irreführend?
c++
c++11
move-semantics
rvalue-reference
c++-faq
Howard Hinnant
quelle
quelle
std::move
bewegt sich das Drei-Argument tatsächlich.std::char_traits::move
std::remove()
, dass die Elemente nicht entfernt werden: Sie müssen immer noch aufrufenerase()
, um diese Elemente tatsächlich aus dem Container zu entfernen. Alsomove
bewegtremove
sich nicht , entfernt sich nicht. Ich hätte den Namenmark_movable()
für gewähltmove
.mark_movable()
verwirrend finden . Es deutet darauf hin, dass es eine dauerhafte Nebenwirkung gibt, bei der es tatsächlich keine gibt.Antworten:
Es ist richtig, dass dies
std::move(x)
nur eine Umwandlung in rvalue ist - genauer gesagt in einen xvalue im Gegensatz zu einem prvalue . Und es ist auch wahr, dass eine Besetzungmove
manchmal die Leute verwirrt. Die Absicht dieser Benennung ist jedoch nicht zu verwirren, sondern Ihren Code lesbarer zu machen.Die Geschichte von
move
geht auf den ursprünglichen Umzugsvorschlag von 2002 zurück . In diesem Artikel wird zunächst die r-Wert-Referenz vorgestellt und anschließend gezeigt, wie Sie effizienter schreiben könnenstd::swap
:Man muss sich daran erinnern, dass zu diesem Zeitpunkt in der Geschichte das einzige, was "
&&
" möglicherweise bedeuten könnte, logisch und . Niemand war mit den r-Wert-Referenzen oder den Auswirkungen des Umwandelns eines l-Werts in einen r-Wert vertraut (ohne eine Kopie zu erstellen, wie dies der Fallstatic_cast<T>(t)
wäre). Die Leser dieses Codes würden also natürlich denken:Beachten Sie auch, dass dies
swap
wirklich nur ein Ersatz für alle Arten von permutationsmodifizierenden Algorithmen ist. Diese Diskussion ist viel , viel größer alsswap
.Dann führt der Vorschlag Syntaxzucker ein, der den ersetzt
static_cast<T&&>
durch etwas Lesbareres ersetzt, das nicht das genaue Was , sondern das Warum vermittelt :Dh
move
ist nur Syntaxzucker fürstatic_cast<T&&>
, und jetzt ist der Code ziemlich suggestiv, warum diese Casts da sind: um die Bewegungssemantik zu ermöglichen!Man muss verstehen, dass im Kontext der Geschichte zu diesem Zeitpunkt nur wenige Menschen den engen Zusammenhang zwischen Werten und Bewegungssemantik wirklich verstanden haben (obwohl das Papier auch versucht, dies zu erklären):
Wenn zu der Zeit
swap
stattdessen so präsentiert wurde:Dann hätten sich die Leute das angeschaut und gesagt:
Der Hauptpunkt:
So wie es war,
move
fragte niemand jemals:Im Laufe der Jahre und als der Vorschlag verfeinert wurde, wurden die Begriffe lWert und rWert in die Wertkategorien verfeinert, die wir heute haben:
(Bild schamlos von dirkgent gestohlen )
Wenn wir heute
swap
genau sagen wollen, was es tut, anstatt warum , sollte es eher so aussehen:Und die Frage, die sich jeder stellen sollte, ist, ob der obige Code mehr oder weniger lesbar ist als:
Oder sogar das Original:
In jedem Fall sollte der Gesellen-C ++ - Programmierer wissen, dass unter der Haube von
move
nichts weiter vor sich geht als eine Besetzung. Und der C ++ - Programmierer für Anfänger, zumindest mitmove
, wird darüber informiert, dass die Absicht darin besteht, sich von der rhs zu entfernen, anstatt von der rhs zu kopieren , auch wenn er nicht genau versteht, wie dies erreicht wird.Wenn ein Programmierer diese Funktionalität unter einem anderen Namen wünscht,
std::move
besitzt er kein Monopol auf diese Funktionalität und es ist keine nicht portable Sprachmagie an ihrer Implementierung beteiligt. Wenn man beispielsweise codierenset_value_category_to_xvalue
und stattdessen verwenden möchte, ist dies trivial:In C ++ 14 wird es noch prägnanter:
Wenn Sie also so geneigt sind, dekorieren Sie Ihre,
static_cast<T&&>
wie Sie es für am besten halten, und vielleicht entwickeln Sie am Ende eine neue Best Practice (C ++ entwickelt sich ständig weiter).Was macht
move
also der generierte Objektcode?Bedenken Sie Folgendes
test
:Kompiliert mit
clang++ -std=c++14 test.cpp -O3 -S
erzeugt dies diesen Objektcode:Wenn nun der Test geändert wird zu:
Es gibt absolut keine Veränderung überhaupt in dem Objektcode. Man kann dieses Ergebnis verallgemeinern auf: Für trivial bewegliche Objekte,
std::move
hat dies keine Auswirkungen.Schauen wir uns nun dieses Beispiel an:
Dies erzeugt:
Wenn Sie es
__ZN1XaSERKS_
durchlaufenc++filt
, entsteht :X::operator=(X const&)
. Kein Wunder hier. Wenn nun der Test geändert wird zu:Dann ändert sich der generierte Objektcode immer noch nicht .
std::move
hat nichts anderes getan,j
als einen r-Wert umzuwandeln, und dannX
bindet dieser r-Wert an den Kopierzuweisungsoperator vonX
.Fügen Sie nun einen Verschiebungszuweisungsoperator hinzu zu
X
:Jetzt ändert sich der Objektcode :
Laufen
__ZN1XaSEOS_
durchc++filt
zeigt , dassX::operator=(X&&)
statt aufgerufen wirdX::operator=(X const&)
.Und das ist alles was es zu
std::move
tun gibt ! Es verschwindet zur Laufzeit vollständig. Die einzige Auswirkung ist die Kompilierungszeit, in der möglicherweise geändert wird, welche Überladung aufgerufen wird.quelle
digraph D { glvalue -> { lvalue; xvalue } rvalue -> { xvalue; prvalue } expression -> { glvalue; rvalue } }
für das Gemeinwohl neu erstellt :) Laden Sie es hier als SVGallow_move
;)movable
.std::move
,rvalue_cast
rvalue_cast
ist seine Bedeutung nicht eindeutig: Welche Art von rvalue gibt es zurück?xvalue_cast
wäre hier ein einheitlicher Name. Leider würden die meisten Menschen zu diesem Zeitpunkt auch nicht verstehen, was es tut. In ein paar Jahren wird meine Aussage hoffentlich falsch.Lassen Sie mich hier nur ein Zitat aus den C ++ 11-FAQ von B. Stroustrup hinterlassen , das eine direkte Antwort auf die Frage von OP ist:
Übrigens, ich habe die FAQ wirklich genossen - es lohnt sich zu lesen.
quelle