当我从函数返回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&,mutex}; } private: T object; mutable std::mutex mutex; };
我们的想法是在std :: pair中明确指定std :: lock_guard作为模板参数,但是将mutex作为相应的构造函数参数提供(实际上,第二个版本不起作用,因为std :: lock_guard不可移动).在这种情况下将使用std::pair::pair
的过载(3).
(另外,因为它是C 17,我建议to use std::scoped_lock
instead of std::lock_guard
).