2014-10-06 9 views
5

consideri il seguente:Perché utilizzare il costruttore di mosse in un'istruzione di reso legale?

#include <iostream> 

#define trace(name) std::cout << #name << " (" << this << "), i = " << i << std::endl 

class C 
{ 
    C(C const&); 
    C& operator=(C const&); 
public: 
    int i; 
    C() : i(42) { trace(CTOR); } 
    C(C&& other) : i(other.i) { trace(MOVE); other.i = 0; } 
    C& operator=(C&& other) { trace(ASGN); other.i = 0; return *this; } 
    ~C() { trace(DTOR); } 
}; 

C 
func1(bool c) 
{ 
    C local; 
    if (c) 
     return local; 
    else 
     return C(); 
} 

int 
main() 
{ 
    C local(func1(true)); 
    return 0; 
} 

Sia MSC e g ++ consentire return local, e utilizzare il costruttore spostamento (come indicato dalla uscita) quando farlo. Mentre questo ha molto senso per me, e penso che probabilmente dovrebbe essere il caso, non riesco a trovare il testo nello standard che lo autorizza. Per quanto posso vedere, l'argomento del costruttore di move deve essere un valore di prvalue (che chiaramente non è) o un valore di x; è in realtà un lvalue, che renderebbe il ritorno altrettanto illegale come C other = local; nel corpo della funzione (che non riesce a compilare).

+0

http://en.wikipedia.org/wiki/Return_value_optimization – IdeaHat

+0

Spiegazione qui: http://en.wikipedia.org/wiki/Return_value_optimization –

+4

Questo non sta eseguendo RVO. ** e utilizzare il costruttore di movimento (come mostrato dall'output) ** – chris

risposta

4

C++ 11 12.8/32: quando i criteri per l'elisione di un'operazione di copia sono soddisfatti o verrebbero soddisfatti salvo il fatto che l'oggetto di origine è un parametro di funzione e l'oggetto da copiare è designato con un valore lvalue, la risoluzione di sovraccarico per selezionare il costruttore per la copia viene eseguita per la prima volta come se l'oggetto fosse designato da un valore valore.

Il ritorno di una variabile automatica locale soddisfa i criteri per elision; trattandolo come se fosse un valore il valore seleziona il costruttore di movimento.

+0

Sono d'accordo, inoltre non vi è alcuna possibilità di omettere completamente la copia/spostamento (p31) poiché non è temporaneo. –

+0

@MarcoA .: Cosa intendi? La copia di una variabile locale per il ritorno può essere eliminata, in base al primo criterio di p31. (Potrebbe non succedere in questo esempio, poiché è possibile restituire due valori diversi e al massimo una di queste copie può essere eli- minata.) –

+0

Mi dispiace, mi riferivo alla terza parte. Ho dimenticato di scriverlo. –

6

Quando si sposta la semantica dove aggiunta a C++ in C++ 11, le decisioni vengono prese in base a dove spostare automaticamente la costruzione.

La regola generale che è stata seguita era che la mossa implicita dovrebbe verificarsi quando copia elision sarebbe legale.

Copia elision è legale quando si dispone di un oggetto anonimo che si sta copiando su un'altra istanza. Il compilatore può legalmente elidere la copia e trattare i due oggetti come uno, con una durata pari all'unione dei due oggetti di una vita.

L'altra volta che la copia di elision è legale è quando si restituisce una variabile locale da una funzione. Questo era noto come NRVO (denominato ottimizzazione del valore di ritorno). Questa ottimizzazione in C++ 03 ti permette di dichiarare un valore di ritorno, ed è costruito direttamente nel luogo in cui va il valore di ritorno. Quando si return retval;, non si verifica alcuna copia.

Questo è praticamente impossibile da fare senza inlining quando si restituiscono più oggetti diversi in punti diversi della funzione.

Tuttavia, quando si sposta la semantica dove aggiunta, questo posto era l'altro punto in cui può verificarsi la mossa implicita. Un return local_var; in una funzione che restituisce una variabile dello stesso tipo di local_var può essere eliminato, e in caso contrario, è possibile passare implicitamente da local_var nel valore restituito.

+0

Capisco la motivazione per permetterlo; la mia domanda era dove nello standard lo diceva specificamente. –

Problemi correlati