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

Nic*_*son 16 c++ lambda shared-ptr c++11

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

在Objective-C中,与C++一样,如果引用成员变量,则会隐式捕获self/ this指针.但是因为Objective-C中的所有对象都是有效的"共享指针",所以要使用C++术语,你可以这样做:

doSomethingAsynchronously(^{
  someMember_ = 42;
});
Run Code Online (Sandbox Code Playgroud)

...并确保在执行块时,您正在访问其成员的对象将处于活动状态.你不必考虑它.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.
});
Run Code Online (Sandbox Code Playgroud)

在这里,您需要记住除了this指针之外还要捕获shared_ptr.是否有一些不那么容易出错的方法来实现这一目标?

eca*_*mur 8

C++的基本原则之一是你不支付你不使用的东西.也就是说,在这种情况下上下文,其中采取了shared_ptrthis不必要应该不会产生任何引用计数的开销.这也意味着它不应该自动发生,即使例如作为一个特征enable_shared_from_this,因为你可能想要将短寿命的lambda传递给算法(for_each等等),在这种情况下lambda不会超出其范围.

我建议调整lambda-wrapper模式 ; 在这种情况下,它用于move捕获一个大对象(如何通过移动"std :: for_each中的lambda捕获std :: unique_ptr"),但它同样可以用于共享捕获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);
  }
};
Run Code Online (Sandbox Code Playgroud)

继承使用enable_shared_this_lambda除了enable_shared_from_this; 然后,您可以明确请求任何长期存在的lambdas共享this:

doSomethingAsynchronously(make_shared_this_lambda([this] {
  someMember_ = 42;
}));
Run Code Online (Sandbox Code Playgroud)


JE4*_*E42 5

Boost用途:

auto self(shared_from_this());
auto l = [this, self] { do(); };
Run Code Online (Sandbox Code Playgroud)

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