簡體   English   中英

移動具有非默認構造 class 保護的構造函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM