• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

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

    履歴 編集

    ラムダ式での*thisのコピーキャプチャ [P0018R3]

    このページは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
    

    関連項目

    参照