Plante réponse (avant qu'il a été modifié) a donné un bon exemple d'un type qui ne devrait pas être mobile: std::mutex
.
Le système d'exploitation natif de mutex type (par exemple, pthread_mutex_t
sur les plate-formes POSIX) peut ne pas être d'emplacement "invariant" sens de l'objet adresse est une partie de sa valeur. Par exemple, l'OS peut garder une liste de pointeurs vers tous initialisé objets mutex. Si std::mutex
contenaient un système d'exploitation natif mutex type comme un membre de données et le type natif, l'adresse doit rester fixe (parce que l'OS gère une liste de pointeurs vers ses mutex) alors std::mutex
aurait pour stocker le natif de mutex type sur le tas si il serait rester au même endroit lors d'un déplacement entre std::mutex
des objets ou de l' std::mutex
ne doit pas se déplacer. Stocker sur le tas n'est pas possible, parce qu'un std::mutex
a constexpr
constructeur et doit être admissible à la constante d'initialisation (c'est à dire initialisation statique) de sorte qu'un global std::mutex
est garanti pour être construit avant l'exécution du programme commence, de sorte que son constructeur ne peut pas utiliser new
. Donc, la seule option qui reste est pour std::mutex
immuable.
Le même raisonnement s'applique à d'autres types qui contiennent quelque chose qui nécessite une adresse fixe. Si l'adresse de la ressource doit rester fixe, ne bouge pas!
Il est un autre argument pour ne pas bouger std::mutex
qui est qu'il serait très difficile de le faire en toute sécurité, parce que vous auriez besoin de savoir que personne n'est d'essayer de verrouiller le mutex au moment où il est déplacé. Depuis les mutex sont l'un des blocs de construction que vous pouvez utiliser pour protéger vos données courses, il serait regrettable qu'ils n'étaient pas à l'abri contre les courses elles-mêmes! Avec un immeuble, std::mutex
vous savez les seules choses que n'importe qui peut faire une fois qu'il a été construit et avant il a été détruit, c'est pour le verrouiller et déverrouiller, et ces opérations sont expressément garanti pour être thread-safe et ne pas introduire de données courses. Ce même argument s'applique à l' std::atomic<T>
objets: à moins qu'ils pourraient être déplacés de manière atomique, il ne serait pas possible de se déplacer en toute sécurité, un autre thread peut être essayer d'appeler compare_exchange_strong
sur l'objet juste au moment où il est déplacé. Donc un autre cas où les types ne doivent pas être mobile est l'endroit où ils sont des éléments de base de sécurité code simultané et doit assurer l'atomicité de l'ensemble des opérations sur celles-ci. Si la valeur de l'objet peut être déplacé à un nouvel objet, à tout moment, vous devrez utiliser une variable atomique de protéger chaque variable atomique afin de savoir si il est sûr de l'utiliser ou il a été déplacé ... et une variable atomique pour protéger cette variable atomique, et ainsi de suite...
Je pense que je serais généraliser à-dire que quand un objet est juste un pur morceau de la mémoire, pas un type qui agit en tant que titulaire d'une valeur ou d'abstraction d'une valeur, il ne fait pas de sens pour le déplacer. Types fondamentaux tels que l' int
ne peuvent pas se déplacer: déplacer n'est qu'une copie. Vous ne pouvez pas arracher les tripes d'un int
, vous pouvez copier sa valeur et puis le mettre à zéro, mais c'est toujours un int
avec une valeur, c'est juste octets de mémoire. Mais un int
est toujours mobiliers dans la langue, parce que d'une copie valide opération de déplacement. Pour les non-copiable types toutefois, si vous ne voulez pas ou ne pouvez pas déplacer le morceau de la mémoire, et que vous ne pouvez pas copier de sa valeur, alors c'est non délocalisables. Un mutex ou atomique variable est un emplacement de mémoire (traités avec des propriétés spéciales) afin de ne pas faire sens pour se déplacer, et n'est pas copiable, il est donc non délocalisables.