安全,异步地使用C ++ 11 lambda [英] Using C++11 lambdas asynchronously, safely

查看:67
本文介绍了安全,异步地使用C ++ 11 lambda的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是从Objective-C的背景来学习C ++ 11的,而我正在努力解决的一件事是C ++ 11 lambda与Object-C块的不同捕获语义。 (请参见此处比较)。

I've come to C++11 from an Objective-C background, and one thing I'm struggling to come to terms with is the different capturing semantics of C++11 lambdas vs Objective-C "blocks". (See here for a comparison).

在Objective-C中,像C ++一样,自身 / 指针。但是由于Objective-C中的所有对象实际上都是共享指针,因此要使用C ++术语,您可以这样做:

In Objective-C, like C++, the self/this pointer is implicitly captured if you refer to a member variable. But because all objects in Objective-C are effectively "shared pointers", to use the C++ terminology, you can do this:

doSomethingAsynchronously(^{
  someMember_ = 42;
});

...,您可以保证正在访问其成员的对象在块执行。您无需考虑。 C ++中的等效项似乎是这样的:

... and you're guaranteed that the object whose member you're accessing will be alive when the block executes. You don't have to think about it. The equivalent in C++ seems to be something like:

// 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。

Here, you need to remember to capture the shared_ptr in addition to the this pointer. Is there some less error-prone way of achieving this?

推荐答案

C ++的一项基本原则是,您不需要支付不使用的费用。这意味着在这种情况下,不需要将 shared_ptr 替换为 this 的情况,不会导致任何引用计数开销。这也意味着,即使例如作为 enable_shared_from_this 的一个功能,因为您可能希望将短暂的lambda传递给算法( for_each 等。)在这种情况下,lambda不会超出其范围。

One of the founding principles of C++ is that you don't pay for what you don't use. That means in this case that contexts where taking a shared_ptr to this is unnecessary shouldn't incur any reference counting overhead. This also means that it shouldn't happen automatically even e.g. as a feature of enable_shared_from_this, since you might want to pass a short-lived lambda to an algorithm (for_each, etc.) in which case the lambda doesn't outlive its scope.

我建议改写 lambda-wrapper模式;在这种情况下,它用于移动捕获大对象(如何通过移动捕获std :: for_each 中的lambda的std :: unique_ptr,但同样可以用于共享捕获 this

I'd suggest adapting the lambda-wrapper pattern; in that case it's used for move capture of a large object (How to capture std::unique_ptr "by move" for a lambda in std::for_each), but it can equally be used for shared capture of 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 ;然后,您可以明确要求任何长寿的lambda共享一个

Use by inheriting enable_shared_this_lambda in addition to enable_shared_from_this; you can then explicitly request that any long-lived lambdas take a shared this:

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

这篇关于安全,异步地使用C ++ 11 lambda的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆