最終更新日時: 2025年07月12日 02時16分44秒 (JST)
Koichi Murase が更新

履歴 編集

function
<future>

# std::future::get(C++11)

    R future::get();
    R& future<R&>::get();
    void future<void>::get();

## 概要

結果を取得する

## 効果

共有状態が準備完了状態(`future_status::ready`)になるまで`wait()`で待機し、共有状態に格納されている値を取得する。

## 戻り値

- `future::get()` ： 共有状態に格納されている値`v`を`std::move(v)`で返す。
- `future<R&>::get()` ： 共有状態に格納されている参照を返す。
- `future<void>::get()` ： 何も返さない。

## 例外

共有状態に例外が格納されていた場合、格納されている例外を送出する。

## 事前条件

- `valid() == true`
  - この条件を満たさなかった場合、処理系によっては`future_error` 例外を投げることがある。

## 事後条件

この関数呼び出し後は共有状態が破棄され、`valid() == false`となること。

つまりこの関数は1オブジェクトにつき1回しか呼び出せない。

## 例

    #include <iostream>
    #include <future>
    #include <thread>
    #include <utility>

    void calc(std::promise<int> p)
    {
      int sum = 0;
      for (int i = 0; i < 10; ++i) {
        sum += i + 1;
      }

      p.set_value(sum); // 結果値を書き込む
    }

    int main()
    {
      std::promise<int> p;
      std::future<int> f = p.get_future();

      // 別スレッドで計算を行う
      std::thread t(calc, std::move(p));

      // calc()によって書き込まれた結果を取得
      std::cout << f.get() << std::endl;

      t.join();
    }

### 出力

    55

## 例：`std::future<R&>`

    #include <iostream>
    #include <future>
    #include <thread>
    #include <utility>

    class Calculator {
      int sum_ = 0;
      std::future<int&> async_calc;

    public:
      void start()
      {
        std::promise<int&> p;
        async_calc = p.get_future();

        std::thread t(&Calculator::calc, this, std::move(p));
        t.detach();
      }

      int get()
      {
        return async_calc.get(); // 結果値への参照を取得する
      }

      void calc(std::promise<int&> p)
      {
        int sum = 0;
        for (int i = 0; i < 10; ++i) {
          sum += i + 1;
        }

        sum_ = sum;
        p.set_value(sum_); // メンバ変数への参照を結果値として書き込む
      }
    };

    int main()
    {
      Calculator c;

      // 非同期に計算を開始する
      c.start();

      // 計算結果を取得する
      int result = c.get();

      std::cout << result << std::endl;
    }

### 出力

    55

## 例：`std::future<void>`

    #include <iostream>
    #include <future>
    #include <thread>
    #include <utility>

    class Calculator {
      int sum_ = 0;
      std::future<void> async_calc;

    public:
      void start()
      {
        std::promise<void> p;
        async_calc = p.get_future();

        std::thread t(&Calculator::calc, this, std::move(p));
        t.detach();
      }

      int get()
      {
        async_calc.get(); // 終了待機のみを行う
        return sum_;
      }

      void calc(std::promise<void> p)
      {
        int sum = 0;
        for (int i = 0; i < 10; ++i) {
          sum += i + 1;
        }

        // メンバ変数として結果を保持し、promiseでは計算終了の通知のみ行う
        sum_ = sum;
        p.set_value();
      }
    };

    int main()
    {
      Calculator c;

      // 非同期に計算を開始する
      c.start();

      // 計算結果を取得する
      int result = c.get();

      std::cout << result << std::endl;
    }

### 出力

    55

## バージョン

### 言語

- C++11

### 処理系

- Clang: ??
- GCC: 4.7.0 ✅
- ICC: ??
- Visual C++: 2012 ✅
  - 2012段階の`std::thread`クラスは、コンストラクタに引数をムーブで渡すことができない。そのため、`promise`オブジェクトはスレッド間の共有オブジェクトにする必要がある。(所有権が曖昧になるため、スタイルとしてはよくない) #737812 - std::thread does not accept std::move

## 参照

- LWG Issue 2096. Incorrect constraints of `future::get` in regard to `MoveAssignable`
  - C++14から、`future::get()`の戻り値が変更された。C++11では「ムーブ代入可能ならムーブで返し、そうでなければコピーで返す」となっていたが、これは現実的ではない制約だった。