[英]Move constructor with protection for non-default-constructible class
假設我有一個不可默認構造的 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;
};
然后,我有一個簡單的互斥鎖:
class Mutex {
public:
void take();
void give();
};
現在,我有一個復合 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();
}
};
這會引發錯誤,因為它會在進入構造函數主體之前嘗試默認構造a
成員。 有沒有辦法用互斥鎖保護a
的移動構造?
您可以在助手 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{} {}
};
如果C
本身由多個字段組成,則將互斥體移出到包裝器 class。 理想情況下,包裝器應該只保留一個 object + 一個互斥鎖。 這使用了您的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));
}
最后是@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.