Câu trả lời của Herb (trước khi nó được chỉnh sửa) thực sự đã đưa ra một ví dụ điển hình về loại không nên di chuyển : std::mutex.
Loại mutex gốc của HĐH (ví dụ: pthread_mutex_ttrên nền tảng POSIX) có thể không phải là "bất biến vị trí" nghĩa là địa chỉ của đối tượng là một phần của giá trị. Ví dụ, HĐH có thể giữ một danh sách các con trỏ tới tất cả các đối tượng mutex được khởi tạo. Nếu std::mutexchứa loại mutex OS gốc là thành viên dữ liệu và địa chỉ của kiểu bản địa phải được cố định (vì HĐH duy trì một danh sách các con trỏ tới mutexes của nó) thì std::mutexsẽ phải lưu trữ kiểu mutex gốc trên heap để nó ở lại cùng một vị trí khi di chuyển giữa std::mutexcác đối tượng hoặc std::mutexkhông được di chuyển. Lưu trữ nó trên heap là không thể, bởi vì một std::mutexngười constexprxây dựng và phải đủ điều kiện để khởi tạo liên tục (nghĩa là khởi tạo tĩnh) để toàn cầustd::mutexđược đảm bảo được xây dựng trước khi bắt đầu thực thi chương trình, vì vậy hàm tạo của nó không thể sử dụng new. Vì vậy, lựa chọn duy nhất còn lại là std::mutexbất động.
Lý do tương tự áp dụng cho các loại khác có chứa một cái gì đó yêu cầu một địa chỉ cố định. Nếu địa chỉ của tài nguyên phải cố định, đừng di chuyển nó!
Có một lập luận khác cho việc không di chuyển std::mutex, đó là sẽ rất khó để làm điều đó một cách an toàn, bởi vì bạn cần biết rằng không ai đang cố gắng khóa mutex tại thời điểm nó được di chuyển. Vì mutexes là một trong những khối xây dựng mà bạn có thể sử dụng để ngăn chặn các cuộc đua dữ liệu, sẽ thật đáng tiếc nếu chúng không an toàn trước chính các cuộc đua! Với một bất động, std::mutexbạn biết những điều duy nhất bất cứ ai có thể làm với nó một khi nó đã được xây dựng và trước khi nó bị phá hủy là khóa nó và mở khóa nó, và những hoạt động đó được đảm bảo rõ ràng là an toàn cho luồng và không giới thiệu các cuộc đua dữ liệu. Lập luận tương tự này áp dụng cho std::atomic<T>các đối tượng: trừ khi chúng có thể được di chuyển nguyên tử, không thể di chuyển chúng một cách an toàn, một luồng khác có thể đang cố gắng gọicompare_exchange_strongtrên đối tượng ngay tại thời điểm nó được di chuyển. Vì vậy, một trường hợp khác mà các loại không nên di chuyển được là ở chỗ chúng là các khối xây dựng mức thấp của mã đồng thời an toàn và phải đảm bảo tính nguyên tử của tất cả các hoạt động trên chúng. Nếu giá trị đối tượng có thể được chuyển sang một đối tượng mới bất cứ lúc nào bạn cần sử dụng biến nguyên tử để bảo vệ mọi biến số nguyên tử để bạn biết liệu có an toàn khi sử dụng nó hay nó đã được di chuyển ... và một biến nguyên tử để bảo vệ biến nguyên tử đó, v.v.
Tôi nghĩ rằng tôi sẽ khái quát để nói rằng khi một đối tượng chỉ là một mảnh bộ nhớ thuần túy, không phải là một loại đóng vai trò là người nắm giữ một giá trị hoặc sự trừu tượng của một giá trị, thì việc di chuyển nó sẽ không có ý nghĩa gì. Các loại cơ bản như intkhông thể di chuyển: di chuyển chúng chỉ là một bản sao. Bạn không thể rip can đảm ra khỏi một int, bạn có thể sao chép giá trị của nó và sau đó đặt nó là không, nhưng nó vẫn là intvới một giá trị, nó chỉ byte của bộ nhớ. Nhưng một intvẫn có thể di chuyểntrong các điều khoản ngôn ngữ vì một bản sao là một hoạt động di chuyển hợp lệ. Tuy nhiên, đối với các loại không thể sao chép, nếu bạn không muốn hoặc không thể di chuyển mảnh bộ nhớ và bạn cũng không thể sao chép giá trị của nó, thì nó không thể di chuyển được. Một mutex hoặc một biến nguyên tử là một vị trí cụ thể của bộ nhớ (được xử lý bằng các thuộc tính đặc biệt) vì vậy không có ý nghĩa để di chuyển, và cũng không thể sao chép, vì vậy nó không thể di chuyển được.