18

についてエラーが発生します

エラー:タイプ'int'の右辺値からのタイプ'int&'の非定数参照の無効な初期化</ p>

から

#include <thread>
#include <iostream>

using namespace std;

void func(int& i){
    cout<<++i<<endl;
}

int main(){
    int x=7;
    thread t(func,x);
    t.join();
    return 0;
}

私にはできないことを理解していますthread(func, 4)x、それは一時的なものではなく、変数です。

-std = c ++11-pthreadでgcc4.7を使用しています

このエラーが発生するのはなぜですか?

4

2 に答える 2

19

std::threadコンストラクターの仕様によると

効果:スレッド型のオブジェクトを構築します。新しい実行スレッドはINVOKEDECAY_COPYDECAY_COPYを実行 、DECAY_COPY( 呼び出しは構築スレッドで評価されます。( std::forward<F>(f)), (std::forward<Args>(args))...)

ここで、DECAY_COPY(x)decay_copy(x)は、次のように定義されている場所を呼び出すことを意味します。

template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }

これが意味するのは、引数が「減衰」してコピーされるということです。つまり、引数は値によって転送され、cv資格を失います。スレッドによって実行されるターゲット関数は参照によってそのパラメーターを取得しようとしているため、参照が値によって渡されたオブジェクトにバインドできないというコンパイラエラーが発生します。

これは仕様によるものであり、デフォルトでは、std::threadgetに渡されるローカル変数は参照ではなく値によって渡されます(つまり、コピーされます)。これにより、新しいスレッドには、スコープ外のローカル変数へのぶら下がり参照がなくなり、未定義の動作が発生します。

reference_wrapper参照によって変数を渡すことが安全であることがわかっている場合は、「減衰」セマンティクスの影響を受けず、ターゲットオブジェクトを参照して変数を転送するを使用して、明示的に渡す必要があります。reference_wrapperを使用して作成できますstd::ref

于 2013-03-06T00:20:35.393 に答える
16

スレッドを作成するときにラップxインします。std::ref

作成するたびstd::threadにすべての変数を参照で取得した場合は、どうなるかを考えてください。スタックローカル変数を渡した場合、それはぶら下がっている参照になり、スレッドがその自動ストレージのスコープを超えた場合、未定義の動作が発生します。変数。これは実際には多く発生し、多くのバグが発生します。代わりにstd::thread、デフォルトでは、すべての引数(変数を含む)を値で取得します(完全な転送を介してマーシャルします)。

std::futureスレッドローカル左辺値コピーを渡すことによってワーカー関数を呼び出すときに、はサイレントに機能する可能性がありますがx、それはかなり混乱します。ワーカータスクはx、参照によって渡されたと思ったものを編集し、x外部には表示されません。タスクの。代わりに、そのエラーメッセージが表示されます。あなたはそれについてあなたの幸運な星に感謝するべきです!

本当に値で何かを取りたくないことを示すために、それをでラップします。これでstd::ref、参照としてワーカー関数に渡されます。std::futureこの場合、参照されるデータが少なくとものワーカータスクが必要とする限り存続するように、参照の存続期間を管理する責任があります。

于 2013-03-05T23:11:45.720 に答える