最終更新日時(UTC):
が更新

履歴 編集

ラムダ式での*thisのコピーキャプチャ(C++17)

概要

C++14までラムダ式で[this]のようにキャプチャをすると、thisポインタがコピーされていた。その場合、非同期処理のような状況で、ラムダ式の関数オブジェクトが呼び出されたときに、thisポインタが指すオブジェクトの寿命が尽きている場合がある。

C++17では[*this]のようにキャプチャすることで、キャプチャ時点での*thisオブジェクトをコピーできるようになった。

[*this]のキャプチャは、[=, *this]のようにデフォルトコピーキャプチャと併用できる。[this, *this]のようなキャプチャは指定できない。

備考

  • [*this]でコピーキャプチャしたオブジェクトは、デフォルトでconstになるので注意。[this]はポインタであるため書き換えができ、非constメンバ関数を呼び出せる。しかし、[*this]はオブジェクトをコピーしてconstとなるため、ラムダ式にmutableを付けない限り、非constメンバ関数を呼び出せない。
  • ラムダ式の関数オブジェクトが呼び出されたときに、thisポインタの寿命が尽きる場合があることが正しい状況では、依然としてstd::weak_ptrのような機能を使用して、生死監視をする必要がある。

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<bool> is_finish;

struct F {
  void start()
  {
    auto proc = [*this]() mutable {
      // てきとうな時間のかかる処理として、[1, 10]の合計値を計算
      int sum = 0;
      for (int i = 1; i <= 10; ++i) {
        sum += i;
      }

      // 処理が終了したらクラス内のメンバ関数を呼び出す。
      // この段階で*thisが有効でなければならない
      onFinish(sum);
    };

    // バックグラウンドスレッドでproc関数オブジェクトを実行する
    std::thread t(proc);
    t.detach();
  }

  void onFinish(int sum)
  {
    std::cout << "finished: " << sum << std::endl;
    is_finish.store(true);
  }
};

int main()
{
  F().start();

  while (!is_finish.load()) {}
  std::cout << "exit" << std::endl;
}

出力

finished: 55
exit

関連項目

参照