[英]Move constructor with protection for non-default-constructible class
Let's imagine I have a non-default-constructible class like so:假设我有一个不可默认构造的 class ,如下所示:
class A {
public:
int k;
A() = delete;
A(int _k): k{_k}{};
A(A const& o) = delete;
A& operator=(A const& o) = delete;
A(A&& o) = default;
A& operator=(A&& o) = default;
};
Then, I have a simple mutex:然后,我有一个简单的互斥锁:
class Mutex {
public:
void take();
void give();
};
Now, I have a composite class, and I want to protect every operation on the A
class (and other members), including move-constructing them:现在,我有一个复合 class,我想保护
A
class(和其他成员)上的每个操作,包括移动构造它们:
class C {
A a;
A b;
Mutex m;
C() = delete;
C(int _k, int _l) : m{}, a{_k}, b{_l} {}
C(C&& other) : m{} { // PROBLEM HERE : use of deleted constructor
other.m.take(); // <-- this disallows the use of initializer list
a{std::move(other.a)};
b{std::move(other.b)};
other.m.give();
}
};
This throws an error because it tries to default-construct the a
member before entering the constructor body.这会引发错误,因为它会在进入构造函数主体之前尝试默认构造
a
成员。 Is there a way to protect the move-construction of a
with the mutex?有没有办法用互斥锁保护
a
的移动构造?
You could do the locking in a helper function:您可以在助手 function 中进行锁定:
class C {
A a;
std::mutex m; // using a standard mutex instead
A A_mover(C&& other) {
std::lock_guard<std::mutex> lock(other.m);
return std::move(other.a); // move into a temporary while locked
}
public:
C() = delete;
C(int _k) : a{_k}, m{} {}
C(C&& other) : a(A_mover(std::move(other))), m{} {}
};
If C
itself is composed of multiple fields, move the mutex out to a wrapper class.如果
C
本身由多个字段组成,则将互斥体移出到包装器 class。 The wrapper should ideally keep only one object + a mutex.理想情况下,包装器应该只保留一个 object + 一个互斥锁。 This uses your
Mutex
as it seems the standard std::mutex
isn't available.这使用了您的
Mutex
,因为标准std::mutex
似乎不可用。
class C {
A a;
A b;
public:
C() = delete;
C(int _k, int _l) : a{_k}, b{_l} {}
C(C&& other) = default;
};
class CLocker {
public:
template<typename...Args>
CLocker(Args...args) : c(std::forward<Args>(args)...) {}
CLocker(CLocker&& other) : c(mover(std::move(other))) {}
private:
struct MutexLockGuard {
MutexLockGuard(Mutex& M) : m(M) { m.take(); }
~MutexLockGuard() { m.give(); }
Mutex& m;
};
C mover(CLocker&& other) {
MutexLockGuard lock(m);
return std::move(other.c); // move into a temporary while locked
}
C c;
Mutex m;
};
int main() {
CLocker cl1(10, 20);
CLocker cl2(std::move(cl1));
}
Finally an option without a wrapper suggested by @Jarod42:最后是@Jarod42 建议的没有包装器的选项:
class MutexLockGuard {
public:
MutexLockGuard(Mutex& M) : m(M) { m.take(); }
~MutexLockGuard() { m.give(); }
private:
Mutex& m;
};
class C {
public:
C() = delete;
C(int _k, int _l) : a{_k}, b{_l}, m{} {}
C(C&& other) : C(MutexLockGuard(other.m), std::move(other)) {}
//^ delegate to protected constructor
protected:
C(MutexLockGuard, C&& other) : // do the moves while the lock is held
a{std::move(other.a)},
b{std::move(other.b)},
m{}
{}
private:
A a;
A b;
Mutex m;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.