我从Objective-C背景来到C ++ 11,而我正在努力解决的一件事是C ++ 11 lambdas与Objective-C“blocks”的不同捕获语义。 (参见here进行比较)。
在Objective-C中,与C ++一样,如果引用成员变量,则会隐式捕获self
/ this
指针。但是因为Objective-C中的所有对象都是有效的“共享指针”,所以要使用C ++术语,你可以这样做:
doSomethingAsynchronously(^{
someMember_ = 42;
});
...并确保在执行块时,您正在访问其成员的对象将处于活动状态。你不必考虑它。 C ++中的等价物似乎是这样的:
// I'm assuming here that `this` derives from std::enable_shared_from_this and
// is already owned by some shared_ptr.
auto strongThis = shared_from_this();
doSomethingAsynchronously([strongThis, this] {
someMember_ = 42; // safe, as the lambda holds a reference to this
// via shared_ptr.
});
在这里,您需要记住除了this指针之外还要捕获shared_ptr。是否有一些不那么容易出错的方法来实现这个目标?
答案 0 :(得分:8)
C ++的一个基本原则是你不为你不使用的东西买单。这意味着在这种情况下,不需要shared_ptr
到this
的上下文不应该引起任何引用计数开销。这也意味着它不应该自动发生,例如作为enable_shared_from_this
的一个特性,因为您可能希望将一个短命的lambda传递给算法(for_each
等),在这种情况下,lambda不会超出其范围。
我建议改编lambda-wrapper pattern;在这种情况下,它用于move
捕获大对象(How to capture std::unique_ptr "by move" for a lambda in std::for_each),但它同样可以用于共享捕获this
:
template<typename T, typename F>
class shared_this_lambda {
std::shared_ptr<T> t; // just for lifetime
F f;
public:
shared_this_lambda(std::shared_ptr<T> t, F f): t(t), f(f) {}
template<class... Args>
auto operator()(Args &&...args)
-> decltype(this->f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
};
template<typename T>
struct enable_shared_this_lambda {
static_assert(std::is_base_of<std::enable_shared_from_this<T>, T>::value,
"T must inherit enable_shared_from_this<T>");
template<typename F>
auto make_shared_this_lambda(F f) -> shared_this_lambda<T, F> {
return shared_this_lambda<T, F>(
static_cast<T *>(this)->shared_from_this(), f);
}
template<typename F>
auto make_shared_this_lambda(F f) const -> shared_this_lambda<const T, F> {
return shared_this_lambda<const T, F>(
static_cast<const T *>(this)->shared_from_this(), f);
}
};
除enable_shared_this_lambda
之外,继承enable_shared_from_this
使用;然后,您可以明确请求任何长寿的lambdas采用共享的this
:
doSomethingAsynchronously(make_shared_this_lambda([this] {
someMember_ = 42;
}));
答案 1 :(得分:4)
Boost使用:
auto self(shared_from_this());
auto l = [this, self] { do(); };
这里提到:What's the reason of using auto self(shared_from_this()) variable in lambda function?
答案 2 :(得分:2)
实际上,这个问题有一个正确的答案。答案与shared_from_this()
绑定具有完全相同的效果(就像使用boost::asio::io_service
时那样)。想一想;与shared_from_this()
绑定的内容是什么?它简单地取代了this
。那么是什么阻止您完全用this
取代shared_from_this()
?
按照你的例子,我更新了以使差异更清晰,而不是:
auto strongThis = shared_from_this();
doSomethingAsynchronously([strongThis, this] () {
this->someMember_ = 42; //here, you're using `this`... that's wrong!
});
这样做:
auto strongThis = shared_from_this();
doSomethingAsynchronously([strongThis] () //notice, you're not passing `this`!
{
strongThis->someMember_ = 42;
});
这里唯一的代价就是您必须使用strongThis->
为所有内容添加前缀。但这是最有意义的方法。