简体   繁体   English

移动具有非默认构造 class 保护的构造函数

[英]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();
    }
       
};

Try it in Coliru在科利鲁试试

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM