首页 > 解决方案 > 为什么不将临时对象传递给另一个线程会导致未定义的行为?

问题描述

下面是引用自C++ Concurrency in Action $2.2的示例

void f(int i,std::string const& s);
void oops(int some_param)
{
  char buffer[1024];
  sprintf(buffer, "%i",some_param);
  std::thread t(f,3,buffer);
  t.detach();
}  

作者说这是未定义的行为:

buffer在这种情况下,传递给新线程的是指向局部变量的指针,并且函数 oops 很有可能会在缓冲区转换为std::string新线程上的 a 之前退出,从而导致未定义的行为解决方案是在将std::string缓冲区传递给 std::thread 构造函数之前强制转换为:

void f(int i,std::string const& s);
void not_oops(int some_param)
{
  char buffer[1024];
  sprintf(buffer,"%i",some_param);
  std::thread t(f,3,std::string(buffer));
  t.detach();
}   

但我对此感到困惑。因为就我而言,这两种形式没有区别:

在第一个代码片段中,当buffer作为参数传递给函数时,它也会生成一个临时std::string对象,并将函数参数绑定到该临时对象。所以它与第二个代码片段完全相同。唯一的区别是临时对象在前一个由编译器隐式生成,后一个由用户显式生成。

标签: c++multithreadingc++11concurrency

解决方案


这里有两个步骤:

  • 无论您传递给std::thread的构造函数,该构造函数都会将其衰减复制到新线程可访问的存储中。
  • 然后,新线程使用这些复制的参数调用可调用对象。

第一个片段复制一个指向缓冲区的指针。调用新线程的可调用对象然后将该指针转换为 a std::string,但到那时缓冲区可能已经消失了。

当保证有效时,第二个片段在原始线程中执行转换。然后临时存储std::stringstd::thread构造函数移动到中间存储中。


推荐阅读