web-dev-qa-db-ja.com

スレッドパラメータとしてのポインタと参照の違い

これは例です:

#include<iostream>
#include<thread>
using namespace std;

void f1(double& ret) {
   ret=5.;
}

void f2(double* ret) {
   *ret=5.;
}

int main() {
   double ret=0.;
   thread t1(f1, ret);
   t1.join();
   cout << "ret=" << ret << endl;
   thread t2(f2, &ret);
   t2.join();
   cout << "ret=" << ret << endl;   
}

そして出力は:

ret=0
ret=5

-O2フラグあり/なしのgcc 4.5.2でコンパイルされています。

これは予想される動作ですか?

このプログラムデータレースは無料ですか?

ありがとうございました

38
Predrag

_std::thread_のコンストラクターは引数の型を推定し、値のコピーを格納します。これは、引数オブジェクトの存続期間が少なくともスレッドの存続期間と同じであることを保証するために必要です。

C++テンプレート関数の引数型推定メカニズムは、型_T&_の引数から型Tを推定します。 _std::thread_へのすべての引数がコピーされてからスレッド関数に渡されるため、f1()およびf2()は常にそのコピーを使用します。

参照の使用を主張する場合は、boost::ref()またはstd::ref()を使用して引数をラップします。

_thread t1(f1, boost::ref(ret));
_

または、単純さを好む場合は、ポインターを渡します。これはboost::ref()またはstd::ref()が舞台裏で行うことです。

86

パラメータをstd::threadへの参照で渡す場合は、それぞれをstd::refで囲む必要があります。

thread t1(f1, std::ref(ret));

詳細 ここ

9
Matteo Italia

これらの状況で明示的なstd::ref()(またはboost::ref())が必要になることは、参照を渡すことは本質的に危険なことなので、実際には非常に便利な安全機能です。

非const参照を使用すると、ローカル変数を渡す危険がかなり頻繁にあります。const参照を使用すると、一時的なものになる可能性があり、別のスレッドで呼び出される関数を作成しているとき(およびbind一般に、しばしば/後で非同期に呼び出される関数)オブジェクトが有効でなくなるという大きな危険があります。

バインディングはきちんと見えますが、エラーがキャッチされる場所(つまり、関数の呼び出し)がエラーが発生した場所(バインディング時)と同じではなく、作業が非常に困難になる可能性があるため、これらのバグを見つけるのは最も困難です正確にどの関数がその時に呼び出されているか、したがって、どこにバインドされているかを調べます。

参照として渡す変数のスコープでスレッドに参加するので、インスタンスでは安全です。したがって、そうであることがわかっている場合は、参照を渡すためのメカニズムがあります。

これは、変更を確認したい言語の機能ではありません。特に、参照によって自動的に取得されると壊れるコピーを作成することに依存する既存のコードがたくさんあるため、明示的な方法が必要になるためです。コピーを強制します)。

9
CashCow