在C++ and Beyond 2012: Herb Sutter - C++ Concurrency的40:30,Herb Sutter根据他的包装成语显示了一个监听类:
template<typename T>
class monitor {
private:
mutable T t;
mutable std::mutex m;
public:
monitor(T t_ = T{}) : t{t_} {}
template<typename F>
auto operator()(F f) const -> decltype(f(t))
{
std::lock_guard<mutex> _{m}; return f(t);
}
}
请注意,构造函数接受T
而不是T&
或T&&
,并且不包含构造函数。我想象的用例是:
monitor<Foo> foo = Foo(...);
由于缺少移动构造函数而失败。
答案 0 :(得分:4)
Sutter示例中的构造函数采用T
而不是T &
或T&&
,因为值语义是C ++中的默认值,并且:
T
。 (有时,可能会有 - 但显然不是在这次谈话中)。T&
- 这意味着其他人无需进入监控器即可访问受监控的数据,即无需锁定,即无需序列化访问... 答案 1 :(得分:1)
只有Herb Sutter才能真正回答这个问题。
如果我不得不猜测,我会说他的理由是:
如果您需要此代码来支持不可复制和不可移动的类型,那么查看std::optional
如何实现对它们的支持可能会有所帮助。
即std::optional
有两个构造函数重载。
一个构造函数重载采用转发引用(即U&&
)并使用std::forward
构造包装类型。这增加了对不可复制类型的支持。
另一个构造函数重载将标记类型std::in_place
和forward
的所有剩余参数直接带到包装类型的构造函数中。
这用于构造包裹类型,因此永远不需要移动。
以下是一些示例代码:https://godbolt.org/g/hWmcTA
#include <utility>
#include <mutex>
template<typename T>
class monitor {
private:
mutable T t;
mutable std::mutex m;
public:
monitor()
: t{}
{ }
template<typename Y>
monitor(Y&& y)
: t{std::forward<Y>(y)}
{ }
template<typename... Args>
monitor(std::in_place_t, Args&&... args)
: t{std::forward<Args>(args)...}
{ }
template<typename F>
auto operator()(F f) const -> decltype(f(t))
{
std::lock_guard<std::mutex> _{m}; return f(t);
}
};
// A non-movable type, just for testing.
struct NonMovable {
NonMovable(int n = 0, double d = 0)
: n_{n}, d_{d}
{ }
NonMovable(const NonMovable&) = delete;
NonMovable(NonMovable&&) = delete;
NonMovable& operator=(const NonMovable&) = delete;
NonMovable& operator=(NonMovable&&) = delete;
private:
int n_;
double d_;
};
int main() {
// Non-movable type.
monitor<NonMovable> m4; //< Good. Uses default constructor.
//monitor<NonMovable> m5{NonMovable{1, 2.2}};//< Bad! Forwarding constructor.
monitor<NonMovable> m6{std::in_place, 1, 2.2};//< Good. In-place constructor.
// And a movable type, just to make sure we didn't break anything.
monitor<int> m1; //< Good. Uses default constructor.
monitor<int> m2{1}; //< Good. Forwarding constructor.
monitor<int> m3{std::in_place, 1}; //< Good. In-place constructor.
}