无法将 std::unique_lock 移动到结构中
Can't move a std::unique_lock into a struct
我正在尝试创建一个非常简单的基本 C++ class 来实现线程安全列表,即当您访问它时自动锁定的列表。不幸的是,编译器不允许我创建 return 一个包含 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>)
我猜这意味着大括号初始值设定项 lists/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&&
,那么我怎么可能调用复制构造函数?
我在 Internet 上找到的大多数资源似乎表明您可以使用 std::move 移动 unique_locks,但似乎没有人解决如何构建包含以下内容的对象的问题unique_lock 通过使用 std::move。我在这里做错了什么?
问题:
在 LockedListAccess
构造函数的上下文中,lock_t&& l
实际上是一个左值。因此,您需要使用 std::move
将其转换回 r 值。一般经验法则:总是 std::move
右值引用和总是 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 }
}
我正在尝试创建一个非常简单的基本 C++ class 来实现线程安全列表,即当您访问它时自动锁定的列表。不幸的是,编译器不允许我创建 return 一个包含 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>)
我猜这意味着大括号初始值设定项 lists/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&&
,那么我怎么可能调用复制构造函数?
我在 Internet 上找到的大多数资源似乎表明您可以使用 std::move 移动 unique_locks,但似乎没有人解决如何构建包含以下内容的对象的问题unique_lock 通过使用 std::move。我在这里做错了什么?
问题:
在 LockedListAccess
构造函数的上下文中,lock_t&& l
实际上是一个左值。因此,您需要使用 std::move
将其转换回 r 值。一般经验法则:总是 std::move
右值引用和总是 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 }
}