17

私は Objective-C の背景から C++11 に来ました。私が同意するのに苦労していることの 1 つは、C++11 ラムダと Objective-C の「ブロック」の異なるキャプチャ セマンティクスです。(比較については、こちらを参照してください)。

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 をキャプチャーすることを忘れないでください。これを達成するためのエラーが発生しにくい方法はありますか?

4

3 に答える 3

8

C++ の基本原則の 1 つは、使用しないものには料金を支払わないということです。つまり、この場合、shared_ptrtoを取るthis必要がないコンテキストでは、参照カウントのオーバーヘッドが発生しないはずです。これはまた、たとえば の機能として、自動的に発生するべきではないことも意味します。これはenable_shared_from_this、短命のラムダをアルゴリズム (for_eachなど) に渡したい場合があるためです。この場合、ラムダはそのスコープを超えません。

ラムダラッパーパターンを適応させることをお勧めします。その場合move、大きなオブジェクトのキャプチャに使用されます ( std::for_each のラムダに対して 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);
  }
};

enable_shared_this_lambdaに加えて継承して使用しenable_shared_from_thisます。次に、長寿命のラムダが shared を取るように明示的に要求できますthis

doSomethingAsynchronously(make_shared_this_lambda([this] {
  someMember_ = 42;
}));
于 2012-12-14T13:01:34.363 に答える
6

ブーストの用途:

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

ここで言及:ラムダ関数で auto self(shared_from_this()) 変数を使用する理由は何ですか?

于 2016-02-17T19:50:51.517 に答える