2010-11-03 4 views
29

Wenn Sie ein abgeleitetes Objekt mit einem Verschiebungskonstruktor haben und das Basisobjekt auch Verschiebungssemantik hat, wie kann der Verschiebungskonstruktor des Basisobjekts aus dem Konstruktor des abgeleiteten Objekts move aufgerufen werden?Konstruktor auf abgeleitetem Objekt verschieben

Ich habe versucht, die naheliegendste Sache zuerst:

Derived(Derived&& rval) : Base(rval) 
{ } 

jedoch diese Copykonstruktor des Basisobjekts aufrufen, um am Ende zu sein scheint. Dann habe ich versucht ausdrücklich std::move hier verwendet wird, wie folgt aus:

Derived(Derived&& rval) : Base(std::move(rval)) 
{ } 

Das funktionierte, aber ich bin verwirrt, warum es notwendig ist. Ich dachte, std::move gibt nur eine R-Wert-Referenz. Aber da in diesem Beispiel rval bereits eine rvalue-Referenz ist, sollte der Aufruf an std::move überflüssig sein. Aber wenn ich std::move hier nicht verwende, ruft es nur den Kopierkonstruktor auf. Warum ist der Anruf an std::move notwendig?

Antwort

29

rval ist kein Rvalue. Es ist ein Lvalue innerhalb des Körpers des Move-Konstruktors. Deshalb müssen wir std :: move explizit aufrufen.

Siehe this. Die wichtige Anmerkung ist

Hinweis oben, dass das Argument x ist als L-Wert im Inneren der Bewegungsfunktionen behandelt, obwohl es als rvalue Referenz Parameter deklariert ist. Deshalb ist es notwendig zu sagen, move (x) statt nur x, wenn übergibt an die Basisklasse. Diese ist eine wichtige Sicherheitsfunktion der Bewegung Semantik entwickelt, um zu verhindern, versehentlich zweimal von einigen benannte Variable bewegen. Alle Bewegungen erfolgen nur von rvalues, oder mit einem expliziten Cast zu rvalue wie mit std :: move. Wenn Sie einen Namen für die Variable haben, ist ein Lvalue.

+0

Nur um eine Notiz unabhängig von move -Konstruktor hinzuzufügen, wenn Sie eine Argumenteingabe als reguläres lvalue (ohne die Verwendung von std :: move (xx)) zur Verfügung stellen, können Sie 'Xyy' lvalue an 'Xyy &&' für eine Funktion binden Definiert als foo (Xyy && xyy). –

0

Sie sollten wirklich std :: forward (obj) anstelle von std :: move (obj) verwenden. Forward gibt den richtigen rvalue oder lvalue zurück, basierend auf dem was obj ist, während move einen lvalue in einen rvalue umwandelt.

+10

In diesem Kontext wollen Sie immer auf einen rvalue. –

+2

So ist die wahre Absicht vorwärts genau was passiert wurde, nicht zu ändern, was übergeben wurde. Vorwärts () tut genau das. Es würde Sie auch in die Praxis versetzen, das zu verwenden, um alle Basisfunktionen aufzurufen, egal, was gerade übergeben wird. Wenn Sie sich angewöhnen, move() aufzurufen, können Fehler entstehen, die schwer zu ermitteln sind Verwenden Sie Templates für eine Funktion, die sowohl auf einen R-Wert als auch auf einen L-Wert einwirken kann.Wenn diese Funktion irrtümlich in einem Objekt übergeben wurde, das ein L-Wert ist, möchte es c Fortsetzung der Ausführung? Nur spielen Teufel ein wenig befürworten – jbreiding

+1

@jbreiding Ich verstehe nichts davon ... Verstand Ausarbeitung Ihrer Erklärung mit einigen Code-Beispielen auf, wenn Std :: bewegen wird fehlschlagen, warum std :: vorwärts ist bevorzugt und wann zu welcher? – aCuria