【问题标题】:Can't move a std::unique_lock into a struct无法将 std::unique_lock 移动到结构中
【发布时间】:2016-08-19 22:02:10
【问题描述】:

我正在尝试创建一个非常简单的基本 C++ 类来实现线程安全列表,即当您访问它时会自动锁定的列表。不幸的是,编译器不允许我创建并返回一个包含unique_lock 的结构。这是我一开始尝试的:

template<typename T>
struct LockedQueue {
    private:
        std::mutex mutex;
        using lock_t = std::unique_lock<std::mutex>;
        std::list<T> underlying_list;
    public:
        struct LockedListAccess {
            private:
                lock_t lock;
            public:
                std::list<T> &access;
        };
        LockedListAccess locked() {
            return LockedListAccess{ lock_t{mutex}, underlying_list };
        }
};

这失败了

no matching function for call to ‘LockedQueue<tcp::socket>::LockedListAccess::LockedListAccess(<brace-enclosed initializer list>)

我猜这意味着结构的大括号初始化列表/C++11 统一初始化不适用于像 std::unique_lock 这样的仅移动类型。所以我尝试为我的结构创建一个显式构造函数,它将 unique_lock 作为右值引用,并将其移动到成员中:

template<typename T>
struct LockedQueue {
    private:
        std::mutex mutex;
        using lock_t = std::unique_lock<std::mutex>;
        std::list<T> underlying_list;
    public:
        struct LockedListAccess {
            private:
                lock_t lock;
            public:
                std::list<T> &access;
                LockedListAccess(lock_t&& l, std::list<T>& a) :
                    lock(l), access(a) {};
        };
        LockedListAccess locked() {
            return LockedListAccess{ std::move(lock_t{mutex}), underlying_list };
        }
};

但是,这也失败了,给了我错误

error: use of deleted function ‘std::unique_lock<_Mutex>::unique_lock(const std::unique_lock<_Mutex>&) [with _Mutex = std::mutex]’

这个编译器错误特别令人困惑,因为它指向包含lock(l), access(a) 的行,因为我试图使用已删除的std::unique_lock 复制构造函数。我将l 声明为lock_t&amp;&amp;,那我怎么可能调用复制构造函数呢?

我在 Internet 上找到的大多数资源似乎都表明您可以使用 std::move 移动 unique_locks,尽管似乎没有人解决如何使用 std::move 构造包含 unique_lock 的对象的问题.我在这里做错了什么?

【问题讨论】:

    标签: c++ c++11 locking move-semantics


    【解决方案1】:

    问题:

    LockedListAccess 构造函数的上下文中,lock_t&amp;&amp; l 实际上是一个左值。因此,您需要使用 std::move 将其转换回 r 值。一般经验法则:总是std::move r-value 引用和总是std::forward 转发引用。

    解决方案:

    LockedListAccess(lock_t&& l, std::list<T>& a) 
        : lock(std::move(l))
        , access(a) 
    {}
    

    您也不需要移动临时锁定对象,因为编译器会自动将临时对象绑定到右值引用。

    这个:

    LockedListAccess locked() {
        return LockedListAccess{ std::move(lock_t{mutex}), underlying_list }
    }
    

    可以变成这样:

    LockedListAccess locked() {
        return LockedListAccess{ lock_t{mutex}, underlying_list }
    }
    

    【讨论】:

    • 哇,这是一个奇怪的语言“功能”。我永远不会想到声明 lock_t&amp;&amp; 的东西会突然变成 lock_t&amp; 只是因为它在构造函数中。对于 std::move 已经是右值的东西,它看起来没有必要。谢谢你教我另一个 C++ 怪癖。
    • 不会变成lock_t&amp;。它仍然是绑定到临时对象的右值引用,但它用作左值。起初这让我感到困惑,但如果你知道左值是什么,这实际上是有道理的。 IE:任何被命名的东西很可能是一个左值,而你的 lock_t&amp;&amp; 的名称是 l;
    猜你喜欢
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 2013-12-29
    • 2012-11-02
    相关资源
    最近更新 更多