我收到一个错误
错误:从'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;
}
我明白我不能做 thread(func, 4)
但是 x
是一个变量,而不是一个临时变量 .
我正在使用gcc 4.7和-std = c 11 -pthread
为什么会出现此错误?
2 回答
std::thread
构造函数的规范说其中DECAY_COPY(x)表示调用
decay_copy(x)
,其中定义为:这意味着参数"decay"被复制,这意味着它们按值转发并失去任何cv资格 . 因为线程运行的目标函数想要通过引用获取其参数,所以会出现编译器错误,指出引用不能绑定到通过value传递的对象 .
这是设计的,所以默认情况下传递给
std::thread
的局部变量通过值传递(即复制)而不是通过引用传递,这样新线程就不会对超出范围的局部变量进行悬空引用,从而导致未定义的行为 .如果您知道通过引用传递变量是安全的,那么您需要使用不受"decay"语义影响的
reference_wrapper
显式地这样做,并且将通过引用转发目标对象来转发变量 . 您可以使用std::ref
创建reference_wrapper
.创建线程时在
std::ref
中包装x
.如果每次创建一个
std::thread
它通过引用获取所有变量时,请考虑会发生什么:如果您传入了一个堆栈局部变量,它将是一个悬空引用,如果该线程超出该自动范围,将导致未定义的行为存储变量 . 这在实践中会发生很多,并导致许多错误 . 相反,std::thread
默认采用(通过完美转发编组)所有参数(包括变量)的值 .通过传入
x
的线程局部左值副本来调用你的worker函数时,std::future
可以默默地工作,但这会非常混乱:worker任务会编辑你认为你通过引用传递的x
,它不会显示在x
之外的任务 . 相反,它有助于您提供该错误消息 . 你应该感谢你的幸运星!为了表明你真的想要不按值取值,你将它包装在
std::ref
中,现在它一直作为参考传递给worker函数 . 在这种情况下,您负责管理引用的生命周期,以便所引用的数据至少持续与std::future
的工作人员任务需要它一样长 .