C++ 使用C+;初始化非常量引用无效+;11线?

C++ 使用C+;初始化非常量引用无效+;11线?,c++,c++11,C++,C++11,我在这件事上犯了个错误 错误:从“int”类型的右值初始化“int&”类型的非常量引用无效 从 #包括 #包括 使用名称空间std; 无效函数(整数和整数){ 创建线程时,不能在std::ref中包装x 如果每次创建std::thread时,它都通过引用获取所有变量,那么想想会发生什么:如果传入堆栈局部变量,它将是一个悬空引用,如果线程超出了自动存储变量的范围,则会导致未定义的行为。这在实践中会发生很多,并导致许多错误。相反,默认情况下,std::thread按值接受(通过完美转发封送)所有参数

我在这件事上犯了个错误

错误:从“int”类型的右值初始化“int&”类型的非常量引用无效

#包括
#包括
使用名称空间std;
无效函数(整数和整数){

创建线程时,不能在
std::ref
中包装
x

如果每次创建
std::thread
时,它都通过引用获取所有变量,那么想想会发生什么:如果传入堆栈局部变量,它将是一个悬空引用,如果线程超出了自动存储变量的范围,则会导致未定义的行为。这在实践中会发生很多,并导致许多错误。相反,默认情况下,
std::thread
按值接受(通过完美转发封送)所有参数(包括变量)

当调用worker函数时,
std::future
可以通过传入
x
的线程本地左值副本来静默工作,但这将非常令人困惑:worker任务将编辑您认为通过引用传递的
x
,并且它不会显示在任务外部的
x
中pfully会给你那个错误信息。你应该为此感谢你的幸运星


为了表明您确实不想按值获取某些内容,您将其包装在
std::ref
中,现在它将作为引用传递给worker函数。在这种情况下,您负责管理引用的生存期,以便引用的数据至少与
std::future一样长
的工作任务需要它。

std::thread
构造函数的规范说

效果:构造thread类型的对象。新的执行线程执行INVOKE
detacy\u COPY
(std::forward(f)),
detacy\u COPY
(std::forward(args))…)
,对detacy\u COPY的调用在构造线程中进行评估

其中detacy\u COPY(x)表示调用
detacy\u COPY(x)
,其中定义为:

template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }
模板类型名称衰减::类型衰减\u副本(T&v)
{return std::forward(v);}
这意味着参数“衰减”和被复制,这意味着它们是按值转发的,并且会丢失任何cv限定。因为线程运行的目标函数希望通过引用获取其参数,因此会出现编译器错误,表示引用无法绑定到按值传递的对象

这是经过设计的,因此默认情况下,传递给
std::thread
的局部变量是通过值传递的(即复制的),而不是通过引用传递的,这样新线程就不会对超出范围的局部变量进行挂起引用,从而导致未定义的行为


如果您知道通过引用传递变量是安全的,那么您需要显式地这样做,使用
reference\u包装器
,它不会受到“衰减”的影响语义,并将通过引用将变量转发到目标对象。您可以使用
std::ref

创建一个
reference\u包装器
,该包装器将修复错误,但问题是为什么它是一个错误。@juanchopanza true--我当时在打电话,所以我键入了一个Alex问题的快速修复程序。现在添加了详细信息。看起来像是实现。@bames53,这种行为是标准所要求的。@JonathanWakely啊,我明白了。我快速查看了
std::thread
的定义,看到了完美的转发,但我没有停下来记住/考虑
decation\u COPY
的重要性。你可以传递一个指针。我真的很想知道为什么标准没有给我们
std::invoke
std::detacy\u copy
…谢谢!我以前从未听说过detacy\u copy。@AlexanderDuchene,
detacy\u copy
不是真正的函数,它只是在标准中用于解释语义。在标准库中找不到它。我也遇到过这个问题,我想补充一点,如果目标函数的参数是const int&或int&,它会起作用。因此我认为非const ref不起作用的原因是向它传递了一个右值。@szli,是的,这正是编译器错误所说的!“从“int”类型的右值。要理解的是,目标函数会以右值的形式传递一个参数副本。
template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }