È ansible std :: spostare oggetti fuori dalle funzioni? (C ++ 11)

Questo programma tenta di spostare una stringa fuori da una funzione e usarla per la costruzione di un’altra stringa:

#include  #include  #include  std::string && Get_String(void); int main(){ std::string str{Get_String()}; std::cout << str << std::endl; return 0; } std::string && Get_String(void){ std::string str{"hello world"}; return std::move(str); } 

Il programma si compila, ma segfaults dopo l’esecuzione.


Questo era il mio fondamento Get_String : Get_String creerà una stringa locale. Una copia di quella stringa dovrà essere creata e restituita prima che la stringa vada fuori campo. Quella copia sarà usata per build la stringa in main. Tuttavia, se ho spostato la stringa fuori dalla funzione, non è necessario eseguire alcuna copia.

Nel tentativo di capire la semantica del movimento, qualcuno potrebbe spiegare perché quello che sto facendo, probabilmente non ha senso. È ansible spostare oggetti da una funzione?


MODIFICARE:
Si compila e funziona correttamente se cambio la firma della funzione da:

 std::string && Get_String(void); 

a

 std::string Get_String(void); 

È ancora più efficiente spostare la stringa durante il ritorno in questo caso?

Dato questo esempio,

 X foo () { X x; return x; } 

il seguente comportamento è garantito:

• Se X ha una copia accessibile o un costruttore di mosse, il compilatore può scegliere di scegliere la copia. Questo è il cosiddetto (named) return value optimization ((N) RVO), che è stato specificato anche prima di C ++ 11 ed è supportato dalla maggior parte dei compilatori.
• Altrimenti, se X ha un costruttore di mosse, x viene spostato.
• Altrimenti, se X ha un costruttore di copia, x viene copiato.
• Altrimenti, viene emesso un errore in fase di compilazione.

Si noti inoltre che la restituzione di un riferimento rvalue è un errore se l’object restituito è un object non statico locale:

 X&& foo () { X x; return x; // ERROR: returns reference to nonexistent object } 

Un riferimento di rvalue è un riferimento e restituirlo mentre si fa riferimento a un object locale significa che si restituisce un riferimento a un object che non esiste più. Non importa se std::move() è usato.

std::move() non sposta realmente l’object; trasforma solo lvalue in rvalues.

Quella funzione Get_String lega un riferimento di rvalue a un object locale della funzione. I riferimenti Rvalue sono utili per cose che stanno per essere distrutte, ma altrettanto male come i riferimenti lvalue per cose che sono già state distrutte.

Per spostare un object locale fuori da una funzione, devi solo tornare per tipo di class:

 std::string Get_String(void) { std::string str{"hello world"}; return str; } 

Se il compilatore non riesce a eliminare completamente la copia / sposta, allora il valore di ritorno che il chiamante ottiene sarà costruito usando un costruttore di mosse, non un costruttore di copia, purché l’espressione di ritorno sia:

  • un temporaneo, o
  • un singolo identificatore che nomina qualcosa con durata di archiviazione automatica (come str sopra), o
  • std::move(something)

(Quindi potresti ancora return std::move(str); essere esplicito, ma qui non è necessario.)