Cosa posso fare con un oggetto spostato?


138

Lo standard definisce esattamente cosa posso fare con un oggetto dopo che è stato spostato? Pensavo che tutto ciò che puoi fare con un oggetto spostato è distruggerlo, ma ciò non sarebbe sufficiente.

Ad esempio, prendi il modello di funzione swapcome definito nella libreria standard:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Ovviamente, deve essere possibile assegnare agli oggetti spostati, altrimenti le linee 2 e 3 fallirebbero. Quindi cos'altro posso fare con gli oggetti spostati? Dove posso trovare esattamente questi dettagli nello standard?

(A proposito, perché è T c = std::move(a);invece che T c(std::move(a));nella riga 1?)

Risposte:


53

Gli oggetti spostati esistono in uno stato non specificato, ma valido. Ciò suggerisce che mentre l'oggetto potrebbe non essere più in grado di fare molto, tutte le sue funzioni membro dovrebbero comunque esibire un comportamento definito - incluso operator=- e tutti i suoi membri in uno stato definito - e richiede comunque la distruzione. Lo standard non fornisce definizioni specifiche perché sarebbe unico per ogni UDT, ma potresti essere in grado di trovare specifiche per i tipi standard. Alcuni contenitori simili sono relativamente evidenti: spostano semplicemente il loro contenuto e un contenitore vuoto è uno stato valido ben definito. Le primitive non modificano l'oggetto spostato.

Nota a margine: credo sia T c = std::move(a)che se il costruttore di mosse (o il costruttore di copie se non viene fornito alcun movimento) è esplicito, la funzione fallirà.


26
Non tutte le sue funzioni membro mostreranno un comportamento definito. Solo quelli senza precondizioni. Ad esempio, probabilmente non vuoi pop_backspostarti da vector. Ma puoi sicuramente scoprire se lo è empty().
Howard Hinnant,

6
@Howard Hinnant: pop_backda un vuoto vectorha comunque un comportamento indefinito, dalla memoria, quindi sono abbastanza sicuro che pop_backda un vettore spostato che mostra un comportamento indefinito sia coerente.
Cucciolo

12
Stiamo discutendo di oggetti spostati. Non oggetti noti in uno stato vuoto. Gli oggetti spostati hanno uno stato non specificato (se non diversamente specificato). [lib.types.movedfrom]
Howard Hinnant,

5
@Howard Non specificato, ma valido, quindi pop_backsi comporta ancora come su qualsiasi vettore valido (può anche essere un vettore vuoto).
Christian Rau,

1
che cosa significa non specificato e valido in questo contesto?
Ankur S

114

17.6.5.15 [lib.types.movedfrom]

Gli oggetti dei tipi definiti nella libreria standard C ++ possono essere spostati da (12.8). Le operazioni di spostamento possono essere specificate in modo esplicito o generate in modo implicito. Se non diversamente specificato, tali oggetti spostati devono essere collocati in uno stato valido ma non specificato.

Quando un oggetto si trova in uno stato non specificato, è possibile eseguire qualsiasi operazione sull'oggetto che non ha precondizioni. Se è presente un'operazione con le condizioni preliminari che si desidera eseguire, non è possibile eseguire direttamente tale operazione poiché non si sa se lo stato non specificato dell'oggetto soddisfa le condizioni preliminari.

Esempi di operazioni che generalmente non hanno precondizioni:

  • distruzione
  • Incarico
  • osservatori const quali get, empty,size

Esempi di operazioni che generalmente hanno precondizioni:

  • dereference
  • pop_back

Questa risposta ora appare in formato video qui: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s


1
Ma potrei semplicemente controllare le condizioni preliminari proprio come con qualsiasi altro oggetto, giusto?
Fredoverflow,

6
@FredOverflow Fintanto che questi stessi controlli non hanno precondizioni, ovviamente.
Christian Rau,

1
@ Chris: Ma in cosa differisce da un oggetto normale, non spostato?
Fredoverflow,

2
May-be dovrebbe essere una domanda separata, ma ciò significa: se ho una stringa con char* buffer;e int length;membri, il mio costruttore / compito di spostamento deve scambiare (o impostare) il valore di entrambi? O sarebbe OK, se la lunghezza non fosse specificata (significa che emptye sizerestituisce valori senza significato)?
UncleBens,

3
@ 6502: non ha senso. Una classe C ++ 03 non "viola lo standard C ++ 0x" perché un ctor di spostamento se generato violerebbe lo standard. E il codice C ++ 03 non sposterà quella classe, quindi non c'è motivo per generare un ctor di spostamento.
Salterio,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.