我有一个带有已删除副本构造函数的类,并且我试图将互斥锁成员放入这样的内容中:
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other) = default;
A& operator=(A &&other) = default;
std::mutex lock;
};
编译器抱怨我试图调用已删除的副本构造函数,我总结说这归因于std :: mutex类型是不可移动的。我如何才能使互斥锁成员与move构造函数一起以最小的麻烦玩呢?我实际上并不希望将互斥锁成员本身移动到新构造的对象中,并且实际上希望每个移动的对象只是构造自己的互斥体
答案 0 :(得分:5)
我实际上并不希望将互斥锁成员本身移动到新构造的对象中,而是实际上希望每个移动的对象只是构造自己的互斥锁
然后只需定义您的move构造函数即可构造一个新的互斥体:
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other)
: lock()
{
}
A& operator=(A &&other) = delete;
std::mutex lock;
};
移动分配仍然是个问题,应该删除即可。除非您能回答以下问题:在为新的互斥成员分配新值时会发生什么?特别是:如果在锁定现有互斥锁的情况下为您分配新值怎么办?
答案 1 :(得分:5)
除了为您的类提供自定义移动操作之外,您还可以创建一个通用包装器:
template <class T>
class PerObject
{
T data;
public:
PerObject() = default;
PerObject(const PerObject&) {}
PerObject& operator= (const PerObject&) { return *this; }
T& operator* () const { return data; }
T* operator-> () const { return &data; }
};
并像这样使用它:
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other) = default;
A& operator=(A &&other) = default;
PerObject<std::mutex> lock;
};
包装器的复制(和移动)操作是无操作的,因此包含包装器的对象将始终包含其开始的对象。
注意事项:但是,根据您的班级使用互斥量的方式,以上内容实际上可能很危险。如果互斥锁用于保护该类中的其他数据,则在将对象分配给该互斥锁时,应该将其锁定,因此无论如何您都必须提供手动移动操作。在这种情况下,代码可能看起来像这样:
struct A {
A(A&& other) : lock{}, /* anything else you need to move-construct */
{
// Note: it might even be necessary to lock `other.lock` before moving from it, depending on your class's exact semantics and expected use.
}
A& operator=(A &&other)
{
if (this == &other) return *this; // Otherwise, double-locking would be possible
// If you need to lock only this object:
std::unique_lock<std::mutex> l(lock);
// Alternatively, if you need to lock both objects:
std::scoped_lock l(lock, other.lock);
// Now move data from other to this
return *this;
}
std::mutex lock;
};
答案 2 :(得分:1)
一种方法是使您的move构造函数在调用时创建新的mutex
。
A(A&& other): lock()
{
//... move other things
}
由于std::unique_ptr()
是可移动的,因此您也可以在std::mutex
上使用struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other) = default;
A& operator=(A &&other) = default;
std::unique_ptr<std::mutex> lock;
};
A::A() : lock(new std::mutex())
。
contrib.layers
使用这种方法,您不会在每次移动对象时创建新的互斥体,这将消除一些开销。