【C++】スレッドに引数を渡す3つの方法(値渡し、参照渡し、ムーブ)

目次

はじめに

C++の std::thread を使って新しいスレッドを起動する際、そのスレッドで実行される関数に、メインスレッドから何らかのデータを渡したい場合がほとんどです。

std::thread のコンストラクタは、2番目以降の引数として、スレッドで実行する関数に渡す引数を取ることができます。しかし、引数の渡し方には注意が必要で、主に以下の3つの方法があります。

  1. 値渡し(コピー): デフォルトの動作。
  2. 参照渡し: std::ref を使う。
  3. ムーブ渡し: std::move を使う。

この記事では、これら3つの引数の渡し方について、それぞれの違いと使い方を解説します。


スレッドに引数を渡すサンプルコード

このコードは、worker_task という関数を3つの異なるスレッドで起動し、それぞれ「値渡し」「参照渡し」「ムーブ渡し」で引数を渡します。

完成コード

#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <memory> // unique_ptr

using namespace std;

// スレッドで実行されるタスク
// 1. int: 値渡し, 2. int&: 参照渡し, 3. unique_ptr<int>: ムーブ渡し
void worker_task(int val, int& ref_val, unique_ptr<int> p_val) {
    cout << "--- スレッド開始 ---" << endl;
    
    val++; // コピーなので、元の変数は変わらない
    ref_val++; // 参照なので、元の変数が変わる
    
    cout << "値渡しの値 (スレッド内): " << val << endl;
    cout << "参照渡しの値 (スレッド内): " << ref_val << endl;
    if (p_val) {
        cout << "ムーブ渡しの値 (スレッド内): " << *p_val << endl;
    }
    cout << "--- スレッド終了 ---" << endl;
}

int main() {
    int value_arg = 10;
    int ref_arg = 20;
    auto ptr_arg = make_unique<int>(30);

    // 1. 値渡し: value_arg のコピーが渡される
    thread th1(worker_task, value_arg, ref(ref_arg), move(ptr_arg));
    
    th1.join();

    cout << "\n--- スレッド終了後の main 関数の値 ---" << endl;
    cout << "値渡しの元の変数 (value_arg): " << value_arg << endl;
    cout << "参照渡しの元の変数 (ref_arg): " << ref_arg << endl;
    if (!ptr_arg) {
        cout << "ムーブ渡しの元のポインタ (ptr_arg): 所有権が移動し、空になりました。" << endl;
    }

    return 0;
}

コードの解説

1. 値渡し(デフォルト)

thread th1(worker_task, value_arg, ...);

  • thread のコンストラクタは、デフォルトで全ての引数をコピーして、新しいスレッドの内部記憶域に格納します。
  • worker_task 内で val++ としても、それはコピーされた値に対する変更なので、main関数内の元の変数 value_arg の値(10)は変わりません。

2. 参照渡し (std::ref)

thread th1(..., ref(ref_arg), ...);

  • スレッド内の関数で、メインスレッドの変数を直接変更したい場合は、引数を std::ref でラップする必要があります。
  • ref(ref_arg) とすることで、ref_arg のコピーではなく、ref_arg への参照がスレッドに渡されます。
  • その結果、worker_task 内で ref_val++ とすると、main関数内の元の変数 ref_arg の値が 21 に変わります。

3. ムーブ渡し (std::move)

thread th1(..., move(ptr_arg));

  • std::unique_ptr のように、コピーできないがムーブ(所有権の移動)は可能なオブジェクトを渡す場合は、std::move を使います。
  • move(ptr_arg) とすることで、ptr_arg が管理していたメモリ領域の所有権が、スレッド内の引数 p_val移動します。
  • 実行後、main関数内の ptr_arg は所有権を失い、空のポインタ(nullptr)になります。

まとめ

今回は、C++のスレッドに関数を渡す際の3つの主要な方法を解説しました。

  • 値渡し(デフォルト): 安全ですが、元の変数は変更できません。
  • 参照渡し (std::ref): スレッドから元の変数を変更したい場合に使います。
  • ムーブ渡し (std::move): unique_ptr など、所有権を移動させる必要がある場合に使います。

thread のコンストラクタが引数をコピーする、という基本動作を理解し、参照やムーブが必要な場合は refmove を明示的に使う、という点を押さえておくことが重要です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次