Відповідь Трави (перш ніж він був відредагований) на насправді дав хороший приклад такого типу , який не повинен бути рухомим: std::mutex.
Нативний тип мутексу ОС (наприклад, pthread_mutex_tна платформах POSIX) може не бути "інваріантним розташуванням", тобто адреса об'єкта є частиною його значення. Наприклад, ОС може зберігати список покажчиків на всі ініціалізовані об'єкти mutex. Якщо std::mutexв якості члена даних міститься вбудований тип мутексу ОС, а адреса основного типу повинна залишатися фіксованою (оскільки ОС підтримує список покажчиків на її мутекси), то або std::mutexдоведеться зберігати нативний тип мутексу у купі, щоб він залишався на те саме місце розташування при переміщенні між std::mutexоб'єктами або std::mutexпереміщення не повинно Збереження його на купі неможливо, тому std::mutexщо у constexprконструктора є конструктор і він повинен мати право на постійну ініціалізацію (тобто статичну ініціалізацію), так що глобальнийstd::mutexгарантовано буде побудовано до запуску програми, тому її конструктор не може використовувати new. Тож єдиний варіант, який залишився - std::mutexце бути нерухомим.
Те ж міркування стосується інших типів, які містять щось, що вимагає фіксованої адреси. Якщо адреса ресурсу повинна залишатися фіксованою, не переміщуйте її!
Є ще один аргумент щодо не переміщення, std::mutexякий полягає в тому, що це було б дуже важко зробити це безпечно, тому що вам потрібно знати, що ніхто не намагається заблокувати мютекс у той момент, коли він переміщується. Оскільки мутекси є одним із будівельних блоків, які ви можете використовувати для запобігання перегонів даних, було б прикро, якби вони не були безпечними проти самих перегонів! З нерухомим std::mutexви знаєте, що єдине, що може зробити хтось після того, як він був побудований і перед його знищенням, - це заблокувати та розблокувати, і ці операції гарантовано, що вони є безпечними для потоків, і не вводять перегони даних. Цей самий аргумент застосовується і до std::atomic<T>об'єктів: якщо б їх не вдалося перенести атомним шляхом, неможливо було б безпечно переміщувати їх, інший потік може намагатися викликатиcompare_exchange_strongна об'єкт прямо в той момент, коли він переміщується. Отже, ще один випадок, коли типи не повинні бути рухомими, це те, що вони є низькорівневими будівельними блоками безпечного одночасного коду і повинні забезпечувати атомність усіх операцій над ними. Якщо значення об'єкта може бути переміщено до нового об'єкта в будь-який час, вам потрібно буде використовувати атомну змінну для захисту кожної атомної змінної, щоб ви знали, чи безпечно це використовувати або переміщено ... та атомну змінну для захисту що атомна змінна і так далі ...
Думаю, я б узагальнив, щоб сказати, що коли об'єкт - це просто чистий фрагмент пам'яті, а не тип, який виступає в якості власника для значення або абстрагування значення, його немає сенсу переміщувати. Основні типи, такі як intнеможливо рухатись: переміщення їх - це лише копія. Ви не можете вирвати нутрощі з int, ви можете скопіювати його значення, а потім встановити його в нуль, але це все-таки intзначення, це лише байти пам'яті. Але intвсе ще рухомиймовними термінами, оскільки копія є дійсною операцією переміщення. Однак для типів, що не підлягають копіюванню, якщо ви не хочете або не можете перемістити частину пам'яті, а також не можете скопіювати її значення, то це неможливо перемістити. Мутекс або атомна змінна - це певне місце пам’яті (оброблене спеціальними властивостями), тому не має сенсу переміщуватися, а також не підлягає копіюванню, тому воно не є рухомим.