我收到一个错误
错误:从'int'类型的右值开始,无效初始化'int&'类型的非const引用
从
#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;
}
Run Code Online (Sandbox Code Playgroud)
我明白我做不到thread(func, 4)但是x变量,不是暂时的.
我正在使用gcc 4.7和-std = c ++ 11 -pthread
为什么会出现此错误?
Jon*_*ely 19
std::thread构造函数的规范说
效果:构造一个thread类型的对象.新的执行线程执行INVOKE
(DECAY_COPY( std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...),并在构造线程中对DECAY_COPY的调用进行评估.
其中DECAY_COPY(x)表示调用decay_copy(x)其定义为:
template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }
Run Code Online (Sandbox Code Playgroud)
这意味着参数"衰变"并被复制,这意味着它们按价值转发并失去任何cv资格.因为线程运行的目标函数想要通过引用获取其参数,所以会得到编译器错误,指出引用不能绑定到由value传递的对象.
这是设计的,因此默认情况下,传递给std::threadget的值传递给get(即复制)而不是通过引用传递,因此新线程不会对超出范围的局部变量进行悬空引用,从而导致未定义的行为.
如果您知道通过引用传递变量是安全的,那么您需要使用reference_wrapper不会受"衰减"语义影响的显式,并且将通过引用转发目标对象来转发变量.您可以创建一个reference_wrapper使用std::ref.
Yak*_*ont 16
x在std::ref创建线程时包装.
如果每次创建std::thread它都会通过引用获取所有变量,那么请考虑会发生什么:如果您传入了一个堆栈局部变量,它将是一个悬空引用,如果该线程超出该自动存储的范围,将导致未定义的行为变量.这在实践中会发生很多,并导致许多错误.相反,std::thread默认情况下,通过值获取(通过完美转发的编组)所有参数(包括变量).
std::future通过传入线程局部左值副本来调用你的worker函数时,可以默默地工作x,但这会很混乱:工作者任务会编辑x你认为你通过引用传递,并且它不会出现在x外面任务.相反,它有助于您提供该错误消息.你应该感谢你的幸运星!
为了表明你真的想要不按值取值,你将它包装进去std::ref,现在它一直作为参考传递给worker函数.在这种情况下,您负责管理引用的生命周期,以便引用的数据至少持续std::future与工作者任务需要它一样长.