当我从函数返回std::lock_guard
中的std::pair
时,我得到了可怕的错误。但是,当我将其打包在一个类中时,我没有任何问题(可以按预期进行编译和运行)。我不明白为什么。详细信息如下:
我设计了一个小的模板类来实现对共享对象的方便锁定和解锁。它不是特别创新,但是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
不能移动有关,但对我来说,它看起来 与我的工作代码完全相同。为什么第二个版本不起作用?
答案 0 :(得分:5)
通过按摩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
作为相应的构造函数参数(实际上,第二个版本不起作用,因为{{ 1}}不可移动)。在这种情况下,将使用std::pair::pair
的重载(3)。
(而且,由于它是C ++ 17,我建议使用to use std::scoped_lock
instead of std::lock_guard
)。
答案 1 :(得分:2)
为什么第二个版本不起作用?
在many overloads for constructing std::pair
中,您的代码无法解析为任何特定的代码。现在,除了在这里Dev Null的正确而直接的解决方案之外,我还要留作进一步的参考:您可以{em> forward-construct 您的 public render() {
let stageWithImage =
<Stage ref={this.konvaStage} width={300} height={250}>
<Layer ref={this.konvaLayer}></Layer>
</Stage>
return ({ stageWithImage })
,同时通过std::lock_guard
您想使用T&
的构造函数的piecewise_construct_t
版本:
std::pair()
注意:此外,我将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()
,因为就返回的内容而言,我们在其中非常明确。
答案 2 :(得分:1)
显着的区别是,在第一种情况下,您传递互斥锁,然后让结果类型自行构造std::lock_guard<std::mutex>
,而在第二种情况下,您自己构造它,然后让结果-尝试尝试移动构建它。
后者不起作用!
幸运的是,修复很简单,只需直接传递互斥锁即可。
顺便说一句,请考虑对auto
进行更多投资以减少噪音。