c ++标准库中的许多类现在都有移动构造函数,例如 -
thread::thread(thread&& t)
但似乎std :: mutex没有。我知道它们不能被复制,但是能够从“make_mutex”函数中返回一个似乎是有意义的。 (不是说它有用,只是它有意义)
为什么std :: mutex没有移动构造函数?
答案 0 :(得分:37)
嗯......主要是因为我不认为他们应该移动。从字面上看。
在某些操作系统中,互斥锁可能被建模为句柄(因此您可以复制它们),但是IIRC会对pthreads互斥锁进行就地操作。如果要重新定位,那么任何线程安全都会立即飞出窗口(其他线程如何知道互斥锁刚改变了它的内存地址......)?
答案 1 :(得分:16)
请记住,C ++不会为你不能使用的东西支付费用。哲学到心。让我们考虑一个假想的平台,它使用不透明的类型来表示互斥体;让我们调用mutex_t
类型。如果在该互斥锁上运行的接口使用mutex_t*
作为参数,例如void mutex_init(mutex_t* mutex);
到'构造'一个互斥体,很可能就是互斥体的地址是唯一用于唯一标识互斥锁的情况。如果是这种情况,则表示mutex_t
不可复制:
mutex_t kaboom()
{
mutex_t mutex;
mutex_init(&mutex);
return mutex; // disaster
}
在执行mutex_t mutex = kaboom();
&mutex
时,无法保证&mutex
与功能块中的std::mutex
值相同。
当一天实现者希望为该平台编写mutex_t
时,如果要求该类型是可移动的,那么这意味着内部std::mutex
必须放在动态分配的内存中,以及所有相关的处罚。
另一方面,虽然现在std::unique_ptr<std::mutex>
不可移动,但很容易返回&#39;函数中的一个:返回std::mutex
。这仍然支付动态分配的成本,但仅限于一个地点。所有其他不需要移动std::mutex
的代码都不必支付此费用。
换句话说,由于移动互斥锁并不是互斥锁的核心操作,不需要T
可移动并不能删除任何功能(感谢不可移动的 std::unique_ptr<T>
=&gt; 移动 std::thread
转换),与直接使用本机类型相比,开销成本最低。
join
可以被类似地指定为不可移动,这将使得典型的生命周期如下:在调用有价值的构造函数之后运行(与执行的线程相关联);在调用detach
或std::vector<std::thread>
后,已分离/加入(与无执行线程相关联)。据我了解,EmplaceConstructible
仍然可用,因为该类型应为std::thread
。
编辑:不正确!该类型仍然需要移动(毕竟重新分配时)。所以对我来说理由足够了:将std::vector
放入std::deque
和{{1}}等容器中是很典型的,因此欢迎使用该类型的功能。