如何在标准::p空气中返回标准::lock_guard
How to return std::lock_guard in a std::pair
当我从函数返回std::pair
中的std::lock_guard
时,我遇到了可怕的错误。但是当我把它打包在一个类中时,我没有问题(按预期编译和工作(。我不明白为什么。详情如下:
我设计了一个小型模板类,以便方便地锁定和解锁共享对象。它不是特别创新,但 C++17 允许它非常紧凑且代码读/写友好:
template <typename T> class Locked {
public:
Locked(T& _object, std::mutex& _mutex)
: object(_object)
, lock(_mutex)
{
}
T& object;
std::lock_guard<std::mutex> lock;
};
template <typename T> class Lockable {
public:
Locked<T> borrow() { return Locked(object, mutex); }
Locked<const T> borrow() const { return Locked(object, mutex); }
private:
T object;
mutable std::mutex mutex;
};
它可以像这样使用:
int main()
{
Lockable<std::vector<int>> lv;
auto [vec, lock] = lv.borrow();
std::cout << vec.size() << std::endl;
}
我的问题是这个。Locked
班很薄。我想我可以使用std::pair
而不是正式的类,如下所示:
#include <iostream>
#include <mutex>
#include <utility>
#include <vector>
template <typename T> class Lockable {
public:
std::pair<T&, std::lock_guard<std::mutex>> borrow()
{ return std::pair(object, std::lock_guard<std::mutex>(mutex)); }
std::pair<const T&, std::lock_guard<std::mutex>> borrow() const
{ return std::pair(object, std::lock_guard<std::mutex>(mutex)); }
private:
T object;
mutable std::mutex mutex;
};
int main()
{
Lockable<std::vector<int>> lv;
auto [vec, lock] = lv.borrow();
std::cout << vec.size() << std::endl;
}
但这会带来可怕的、难以解析的错误。我认为这与std::lock_guard
不可移动有关,但对我来说,它看起来与我的工作代码一模一样。为什么第二个版本不起作用?
通过一些按摩Lockable
编译:
template <typename T>
class Lockable {
public:
auto borrow() { return std::pair< T&, std::lock_guard<std::mutex>>{object, mutex}; }
auto borrow() const { return std::pair<const T&, std::lock_guard<std::mutex>>{object, mutex}; }
private:
T object;
mutable std::mutex mutex;
};
活生生的例子。
这个想法是显式指定std::lock_guard
作为std::pair
中的模板参数,但馈送mutex
作为相应的构造函数参数(事实上,第二个版本不起作用,因为std::lock_guard
不可移动(。在这种情况下,将使用std::pair::pair
的重载 (3(。
(另外,由于它是C++17,我建议使用std::scoped_lock
而不是std::lock_guard
(。
为什么第二个版本不起作用?
在构造std::pair
的许多重载中,您的代码无法解析为任何特定的重载。现在,除了 Dev Null 正确而直接的解决方案之外,我将其留作进一步参考: 您可以使用std::pair()
构造函数的piecewise_construct_t
版本,在以您想要的方式传递T&
的同时,向前构造您的std::lock_guard
:
template <typename T> class Lockable {
public:
auto borrow()
{
return std::pair<T&, std::lock_guard<std::mutex>>(
std::piecewise_construct,
std::forward_as_tuple(object), std::forward_as_tuple(mutex));
}
auto borrow() const
{
return std::pair<T&, std::lock_guard<std::mutex>>(
std::piecewise_construct,
std::forward_as_tuple(object), std::forward_as_tuple(mutex));
}
private:
T object;
mutable std::mutex mutex;
};
注意:此外,我将borrow()
的返回类型更改为auto
,因为我们在返回的内容方面足够明确。
显著的区别在于,在第一种情况下,您传递互斥锁,并让结果类型自行构造std::lock_guard<std::mutex>
,而在第二种情况下,您自己构造它,然后让结果类型尝试移动构造它。
后者行不通!
幸运的是,修复是微不足道的,只需直接传递互斥锁即可。
顺便说一句,考虑在auto
上多投资一点以减少噪音。
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 返回标准::移动(m_field)还是返回m_field?
- 我应该返回什么而不是标准::shared_ptr<>&?
- 标准::p空气<自动,自动>返回类型
- 如何在C++中执行命令并获取命令的返回代码标准输出和标准
- 如何在标准::p空气中返回标准::lock_guard
- 我可以从标准::访问返回汽车吗?
- 是否有一些东西限制了未来引入多个返回值C++标准?
- 无法返回派生类型的标准::unique_ptr<>
- C 标准:通过复制返回以初始化无RVO的参考:是否有任何副本
- 如何重置标准::计数返回值
- 将窗口的样式从标准更改为没有标题栏和返回
- registerPointPickingCallback (PCLViewer::callback_Test,(void*)&viewer);返回 C3687 非标准语法;使用"&"创建指向成员的指针
- 迭代器的标准接口::operator*返回的比T&和std::p air更多
- 标准::数组是否可安全返回
- 如何从地图返回标准::p空气的指针并将其放入vector<*std::p air...>
- C++标准是否保证函数返回值具有常量地址?
- C++11 标准中的哪些条款允许我消除下面“A::operator-()”中“返回”语句中的“A”
- 标准库对象作为返回类型和函数参数
- C++11 标准::regex_match 返回额外的字符