Ist bar
ein R-Wert oder ein L-Wert?
Die Frage beantwortet sich von selbst. Was auch immer einen Namen hat, ist ein Wert (1). Also bar
ist ein Lvalue. Sein Typ ist "rvalue Verweis auf string
", aber es ist ein Lvalue dieses Typs.
Wenn Sie es als ein R-Wert behandeln wollen, müssen Sie std::move()
, um es anzuwenden.
Wenn Sie irgendeine Operation an einer rvalue Referenz durchführen können, dass man auf einer L-Wert-Referenz, was der Punkt zwischen den beide mit dem „& &“ statt nur eine „&“ bei der Differenzierung ist?
Dies hängt von Ihrer Definition von "Ausführen einer Operation" ab. Ein L-Wert-Referenz und ein (benannt) rvalue Referenz sind ziemlich identisch, wie man sie in Ausdrücken verwenden können, aber sie unterscheiden sich viel in dem, was an sie binden können. Lvalues können an lvalue-Referenzen binden, rvalues können an rvalue-Referenzen binden (und alles kann an einen lvalue-Verweis an const
gebunden werden). Das heißt, Sie können keinen Rvalue an eine Lvalue-Referenz binden oder umgekehrt.
Reden wir über einen Funktionsparameter von rvalue Referenztyp (wie Ihre bar
). Der wichtige Punkt ist nicht, was bar
ist, sondern was Sie über den Wert wissen, auf den sich bar
bezieht. Da bar
eine Rvalue-Referenz ist, wissen Sie sicher, dass, was auch immer daran gebunden ein Rvalue ist. Das bedeutet, dass es zerstört werden muss, wenn der vollständige Ausdruck endet, und Sie können es sicher als einen Rvalue behandeln (indem Sie seine Ressourcen usw. stehlen).
Wenn Sie nicht derjenige, dies zu bar
direkt zu tun, sondern wollen nur bar
weitergeben müssen, haben Sie zwei Möglichkeiten: Entweder Sie mit bar
getan, und dann sollten Sie das nächste sagen, wer es empfängt, es ist an einen rvalue — do std::move(bar)
gebunden. Oder Sie müssen mehr Dinge mit bar
zu tun, und so wollen Sie nicht, dass jemand zwischendurch seine Ressourcen unter Ihnen zu stehlen, so behandeln sie nur als L-Wert — bar
.
Um es zusammenzufassen: Der Unterschied ist nicht in dem, was Sie mit der Referenz tun können, sobald Sie es haben. Der Unterschied ist, was an die Referenz binden kann.
(1) Eine gute Faustregel mit kleinen Ausnahmen: Aufzählungen Namen haben, aber sind rvalues. Klassen, Namespaces und Klassenvorlagen haben Namen, sind aber keine Werte.
Der gesamte Punkt von rvalues ist, Bewegungssemantik zu erlauben, sie sind in den meisten Arten (außer ihrem Typ) gerade Verweisungen. – Guvante
@Guvante [MikeSeymour] (http://StackOverflow.com/users/204847/mike-seymour) 's Antwort half mir, das zu verstehen. Aber wie bei dem Kommentar, den ich ihm geschrieben habe, würde das nicht zu Problemen führen, wenn wir es zweimal konstruieren würden? Sprich: 'string temp1 (bar), temp2 (bar);' –
In deinem Beispiel bewegst du dich nicht zweimal, du kopierst zweimal, da 'bar' ein lvalue ist (sein Typ ist ein rvalue, seltsam, weiß ich). Wenn Sie 'std :: move' zweimal aufgerufen haben, könnten Sie jedoch Probleme bekommen. – Guvante