繁体   English   中英

安全地异步使用C ++ 11 lambdas

[英]Using C++11 lambdas asynchronously, safely

我从Objective-C背景来到C ++ 11,而我正在努力解决的一件事是C ++ 11 lambdas与Objective-C“blocks”的不同捕获语义。 (见这里进行比较)。

在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。 是否有一些不那么容易出错的方法来实现这一目标?

C ++的基本原则之一是你不支付你不使用的东西。 这意味着在这种情况下,不需要将shared_ptr带到this上下文不应引起任何引用计数开销。 这也意味着它不应该自动发生,即使是作为enable_shared_from_this一个特性,因为你可能想要将一个短命的lambda传递给一个算法( for_each等),在这种情况下lambda不会比它的范围更长。

我建议调整lambda-wrapper模式 ; 在这种情况下它是用于move大型物体的捕捉( 如何捕获的std ::的unique_ptr“的举动”在的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_from_this enable_shared_this_lambda ,还可以通过继承enable_shared_this_lambdaenable_shared_from_this ; 然后你可以明确地要求任何长寿的lambdas分享this

doSomethingAsynchronously(make_shared_this_lambda([this] {
  someMember_ = 42;
}));

Boost使用:

auto self(shared_from_this());
auto l = [this, self] { do(); };

这里提到: 在lambda函数中使用auto self(shared_from_this())变量的原因是什么?

实际上,这个问题有一个正确的答案。 答案与shared_from_this()绑定具有完全相同的效果(就像使用boost::asio::io_service )。 想一想; shared_from_this()绑定的内容是什么? 它简单地取代了this 那么是什么阻止你完全用shared_from_this()替换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->为所有东西加前缀。 但这是最有意义的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM