c++ - 为什么不将临时对象传递给另一个线程会导致未定义的行为?

标签 c++ multithreading c++11 concurrency

下面是引用自 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();
}  

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

In this case, it’s the pointer to the local variable buffer that’s passed through to the new thread, and there’s a significant chance that the function oops will exit before the buffer has been converted to a std::string on the new thread, thus leading to undefined behavior. The solution is to cast to std::string before passing the buffer to the std::thread constructor:

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对象,并将函数参数绑定(bind)到该对象上临时对象。所以它与第二个代码片段完全相同。唯一的区别是前一个中的临时对象是由编译器隐式生成的,而后一个是由用户显式生成的。

最佳答案

这里有两个步骤:

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

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

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

关于c++ - 为什么不将临时对象传递给另一个线程会导致未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50036132/

相关文章:

c++ - 什么是指针引用?

c++ - 我对 C++ catch 子句、异常类系列和销毁的使用是否正常?

ios - 如何在 iOS 中按特定顺序异步下载文件?

multithreading - 在为 Runnable 提供 lambda 时,为什么我不必重写 run 方法?

c++ - 使用命名空间和 using 指令不适用于 std::enable_if_t

c++ - 在其他函数或循环中构造 lambda 时是否存在性能问题?

c++ - 有没有办法将 C++11 代码重构为可以由功能较弱的编译器编译的 C++ 代码?

c++ - 我是否必须为 C++ 中的派生类编写相同的构造函数?

java - 这个java阻塞队列变体可能吗?

c++ - 在处理 std::initializer_list 的元素的范围内使用 "const auto&"是否是一个好习惯