La risposta di erbe (prima che venisse modificato) in realtà ha dato un buon esempio di un tipo che non dovrebbe essere mobile: std::mutex.
Il tipo di mutex nativo del sistema operativo (ad esempio pthread_mutex_tsu piattaforme POSIX) potrebbe non essere "invariante di posizione", il che significa che l'indirizzo dell'oggetto fa parte del suo valore. Ad esempio, il sistema operativo potrebbe mantenere un elenco di puntatori a tutti gli oggetti mutex inizializzati. Se std::mutexcontenesse un tipo di mutex del sistema operativo nativo come membro di dati e l'indirizzo del tipo nativo deve rimanere fisso (poiché il sistema operativo mantiene un elenco di puntatori ai suoi mutex), l'uno o l'altro std::mutexdovrebbe archiviare il tipo di mutex nativo sull'heap in modo che rimanga a la stessa posizione quando spostato tra gli std::mutexoggetti o std::mutexnon deve muoversi. Memorizzarlo sull'heap non è possibile, perché a std::mutexha un constexprcostruttore e deve essere idoneo all'inizializzazione costante (ovvero inizializzazione statica) in modo che un globalestd::mutexè garantito per essere costruito prima che inizi l'esecuzione del programma, quindi il suo costruttore non può usarlo new. Quindi l'unica opzione rimasta è quella std::mutexdi essere immobili.
Lo stesso ragionamento si applica ad altri tipi che contengono qualcosa che richiede un indirizzo fisso. Se l'indirizzo della risorsa deve rimanere fisso, non spostarlo!
C'è un altro argomento per non muoversi, std::mutexche è che sarebbe molto difficile farlo in sicurezza, perché dovresti sapere che nessuno sta cercando di bloccare il mutex nel momento in cui viene spostato. Dato che i mutex sono uno dei mattoni che puoi usare per prevenire le gare di dati, sarebbe sfortunato se non fossero al sicuro contro le gare stesse! Con un immobile std::mutexconosci le uniche cose che chiunque può farci una volta che è stato costruito e prima che sia stato distrutto è bloccarlo e sbloccarlo, e quelle operazioni sono esplicitamente garantite come thread-safe e non introdurre gare di dati. Lo stesso argomento si applica agli std::atomic<T>oggetti: a meno che non possano essere spostati atomicamente, non sarebbe possibile spostarli in modo sicuro, un altro thread potrebbe tentare di chiamarecompare_exchange_strongsull'oggetto nel momento in cui viene spostato. Quindi un altro caso in cui i tipi non dovrebbero essere mobili è quello in cui sono elementi costitutivi di basso livello di codice concorrente sicuro e devono garantire l'atomicità di tutte le operazioni su di essi. Se il valore dell'oggetto può essere spostato su un nuovo oggetto in qualsiasi momento, dovrai utilizzare una variabile atomica per proteggere ogni variabile atomica in modo da sapere se è sicuro utilizzarla o è stata spostata ... e una variabile atomica per proteggere quella variabile atomica e così via ...
Penso che generalizzerei per dire che quando un oggetto è solo un puro pezzo di memoria, non un tipo che funge da supporto per un valore o astrazione di un valore, non ha senso spostarlo. Tipi fondamentali come intnon possono muoversi: spostarli è solo una copia. Non puoi strappare le budella da un int, puoi copiarne il valore e quindi impostarlo su zero, ma è ancora un intcon un valore, sono solo byte di memoria. Ma un intè ancora mobilenei termini della lingua perché una copia è un'operazione di spostamento valida. Per i tipi non copiabili, tuttavia, se non si desidera o non è possibile spostare il pezzo di memoria e non è possibile copiarne il valore, non è mobile. Un mutex o una variabile atomica è una posizione specifica della memoria (trattata con proprietà speciali), quindi non ha senso spostarsi e non è nemmeno copiabile, quindi non è mobile.