2010-11-03 14 views
29

Quando si dispone di un oggetto derivato con un costruttore di movimento e anche l'oggetto di base ha semantica di spostamento, qual è il modo corretto per chiamare il costruttore di spostamento dell'oggetto di base dal costruttore di movimento dell'oggetto derivato?Sposta il costruttore sull'oggetto derivato

ho provato la cosa più ovvia prima:

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

Tuttavia, questo sembra finire per chiamare copia costruttore dell'oggetto Base. Poi ho provato in modo esplicito utilizzando std::move qui, in questo modo:

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

Questo ha funzionato, ma io sono confuso perché è necessario. Ho pensato che std::move restituisca semplicemente un riferimento di rvalue. Ma poiché in questo esempio rval è già un riferimento di rvalue, la chiamata a std::move dovrebbe essere superflua. Ma se non uso std::move qui, chiama semplicemente il costruttore di copie. Quindi, perché è necessaria la chiamata a std::move?

risposta

29

rval non è un valore. È un Lvalue all'interno del corpo del costruttore di mosse. Ecco perché dobbiamo invocare esplicitamente std :: move.

Refer this. La nota importante è

nota sopra che l'argomento x è trattata come valore assegnabile interna alle funzioni spostare , anche se è dichiarata come parametro di riferimento rvalue . Ecco perché è necessario dire move (x) invece di solo x quando passa alla classe base. Questo è una funzionalità di sicurezza chiave della semantica di spostamento progettata per impedire lo spostamento accidentale dello da una variabile denominata di . Tutte le mosse si verificano solo da rvalue o con un cast esplicito per il rvalue come l'utilizzo di std :: move. Se hai un nome per la variabile, è un lvalue.

+0

Solo per aggiungere una nota indipendentemente dal costruttore di mosse se si fornisce un argomento come lvalue regolare (non usando lo std :: move (xx)) si otterrà "impossibile associare 'Xyy' lvalue a 'Xyy &&' per una funzione definito come foo (Xyy && xyy). –

0

Dovresti davvero usare std :: forward (obj) piuttosto che std :: move (obj). Forward restituirà il valore corretto o lvalue in base al quale obj è mentre move trasformerà un lvalue in un valore.

+10

In questo contesto si vuole sempre eseguire il cast di un valore. –

+2

Quindi il vero intento è esattamente quello che è stato passato per non cambiare quello che è stato passato. Avanti () fa esattamente questo. ti metterebbe anche in pratica nell'usare quello per chiamare tutte le funzioni di base, indipendentemente da ciò che è passato. Prendere l'abitudine di chiamare move() potrebbe produrre errori che potrebbero essere difficili da rintracciare.Questo ti sarà utile se volessi usa i modelli su una funzione che può agire sia su un valore di rvalue che su un valore di l. Se questa violazione è stata erroneamente passata in un oggetto che è un lvalue, vorrebbe che fosse c continua esecuzione? Sto solo facendo diavolo difendere un po ' – jbreiding

+1

@jbreiding Non capisco niente di tutto questo ... mente elaborando la tua spiegazione con alcuni esempi di codice su quando std :: move fallirà, perché std :: forward è preferito e quando usare quale? – aCuria

Problemi correlati