A resposta de Herb (antes de ser editado) realmente deu um bom exemplo de um tipo que não deve ser móvel: std::mutex.
O tipo mutex nativo do sistema operacional (por exemplo, pthread_mutex_tnas plataformas POSIX) pode não ser "invariável no local", o que significa que o endereço do objeto faz parte do seu valor. Por exemplo, o sistema operacional pode manter uma lista de ponteiros para todos os objetos mutex inicializados. Se std::mutexcontivesse um tipo de mutex do SO nativo como membro de dados e o endereço do tipo nativo std::mutexdevesse permanecer fixo (porque o SO mantém uma lista de ponteiros para os mutexes), seria necessário armazenar o tipo de mutex nativo no heap para que ele permanecesse em o mesmo local quando movido entre std::mutexobjetos ou o std::mutexnão deve se mover. Não é possível armazená-lo no heap, porque a std::mutexpossui um constexprconstrutor e deve ser elegível para inicialização constante (ou seja, inicialização estática) para que um globalstd::mutexé garantido para ser construído antes do início da execução do programa, portanto, seu construtor não pode usá-lo new. Portanto, a única opção que resta é std::mutexser imóvel.
O mesmo raciocínio se aplica a outros tipos que contêm algo que requer um endereço fixo. Se o endereço do recurso precisar permanecer fixo, não o mova!
Há outro argumento para não se mexer std::mutex: seria muito difícil fazê-lo com segurança, porque você precisaria saber que ninguém está tentando bloquear o mutex no momento em que está sendo movido. Como os mutexes são um dos blocos de construção que você pode usar para evitar corridas de dados, seria lamentável se eles não estivessem seguros contra as próprias corridas! Com um imóvel, std::mutexvocê sabe que as únicas coisas que alguém pode fazer depois que ele for construído e antes de ser destruído é bloqueá-lo e desbloqueá-lo, e essas operações garantem explicitamente a segurança de threads e a não introduzir corridas de dados. Esse mesmo argumento se aplica aos std::atomic<T>objetos: a menos que eles possam ser movidos atomicamente, não seria possível movê-los com segurança, outro encadeamento pode estar tentando chamarcompare_exchange_strongno objeto no momento em que está sendo movido. Portanto, outro caso em que os tipos não devem ser móveis é onde eles são blocos de construção de baixo nível de código simultâneo seguro e devem garantir a atomicidade de todas as operações neles. Se o valor do objeto puder ser movido para um novo objeto a qualquer momento, você precisará usar uma variável atômica para proteger todas as variáveis atômicas, para saber se é seguro usá-lo ou se foi movido ... e uma variável atômica para proteger essa variável atômica, e assim por diante ...
Eu acho que generalizaria para dizer que quando um objeto é apenas um pedaço de memória pura, não um tipo que atua como detentor de um valor ou abstração de um valor, não faz sentido movê-lo. Tipos fundamentais como intnão podem se mover: movê-los é apenas uma cópia. Você não pode arrancar as tripas de um int, pode copiar seu valor e depois defini-lo como zero, mas ainda é um intcom um valor, são apenas bytes de memória. Mas um intainda é móvelnos termos do idioma porque uma cópia é uma operação de movimentação válida. No entanto, para tipos não copiáveis, se você não deseja ou não pode mover o pedaço de memória e também não pode copiar seu valor, ele não é móvel. Um mutex ou uma variável atômica é um local específico da memória (tratado com propriedades especiais), portanto, não faz sentido mover-se e também não é copiável, portanto, não é móvel.