我很惊讶这没有出现在我的搜索结果中,我认为之前有人会问过这个问题,因为 C++11 中 move 语义的用处:
我什么时候必须(或者对我来说是个好主意)在 C++11 中使类不可 move ?
(除了与现有代码的兼容性问题之外的其他原因。)
最佳答案
Herb 的回答(在编辑之前)实际上给出了一个不应该 move 的类型的好例子: std::mutex
。
操作系统的 native 互斥类型(例如 POSIX 平台上的 pthread_mutex_t
)可能不是“位置不变”,这意味着对象的地址是其值的一部分。例如,操作系统可能会保存一个指向所有初始化互斥对象的指针列表。如果 std::mutex
包含作为数据成员的 native 操作系统互斥类型,并且 native 类型的地址必须保持固定(因为操作系统维护指向其互斥的指针列表),则 std::mutex
必须将 native 互斥类型存储在堆上,因此它将在 std::mutex
对象之间 move 时保持在同一位置,或者 std::mutex
不得 move 。将它存储在堆上是不可能的,因为 std::mutex
有一个 constexpr
构造函数,并且必须符合常量初始化(即静态初始化)的条件,这样才能保证在程序的构造函数开始之前使用全局 std::mutex
构造函数new
。所以剩下的唯一选择是 std::mutex
不可 move 。
相同的推理适用于包含需要固定地址的内容的其他类型。如果资源的地址必须保持固定,请不要 move 它!
不 move std::mutex
的另一个论点是很难安全地做到这一点,因为您需要知道在 move 互斥锁时没有人试图锁定它。由于互斥体是您可以用来防止数据竞争的构建块之一,如果它们本身对竞争不安全,那将是不幸的!对于不可 move 的 std::mutex
,您知道任何人在它被构造后和销毁之前唯一能做的事情就是锁定和解锁它,并且这些操作明确保证是线程安全的,不会引入数据竞争。同样的论点适用于 std::atomic<T>
对象:除非它们可以原子地 move ,否则不可能安全地 move 它们,另一个线程可能会在对象被 move 的那一刻试图在对象上调用 compare_exchange_strong
。因此,类型不应该是可 move 的另一种情况是它们是安全并发代码的低级构建块,并且必须确保对它们的所有操作的原子性。如果对象值可能随时被 move 到一个新对象,您需要使用原子变量来保护每个原子变量,以便您知道使用它是否安全或它是否已被 move ......以及一个原子变量来保护那个原子变量,等等......
我想我可以概括地说,当一个对象只是一块纯粹的内存,而不是一种充当值的持有者或值的抽象的类型时, move 它是没有意义的。基本类型如 int
不能 move : move 它们只是一个拷贝。您无法从 int
中删除胆量,您可以复制其值然后将其设置为零,但它仍然是一个带有值的 int
,它只是内存字节。但是 int
在语言术语中仍然是可 move 的,因为拷贝是有效的 move 操作。但是,对于不可复制的类型,如果您不想或不能 move 这块内存并且也不能复制其值,则它是不可 move 的。互斥体或原子变量是内存的特定位置(使用特殊属性处理),因此 move 没有意义,也不可复制,因此不可 move 。
关于c++ - 何时在 C++11 中使类型不可 move ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14302834/