最終更新日時: 2025年07月10日 10時26分30秒 (JST)
Koichi Murase が更新

履歴 編集

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

このページはC++17に採用された言語機能の変更を解説しています。

のちのC++規格でさらに変更される場合があるため関連項目を参照してください。

## 概要

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

## 関連項目

- C++11 ラムダ式

## 参照

- P0018R0 Lambda Capture of `*this` by Value
- P0018R1 Lambda Capture of `*this` by Value
- P0018R2 Lambda Capture of `*this` by Value
- P0018R3 Lambda Capture of `*this` by Value as `[=,*this]`