c++ - 为什么不将临时对象传递给另一个线程会导致未定义的行为?
问题描述
下面是引用自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
对象,并将函数参数绑定到该临时对象。所以它与第二个代码片段完全相同。唯一的区别是临时对象在前一个由编译器隐式生成,后一个由用户显式生成。
解决方案
这里有两个步骤:
- 无论您传递给
std::thread
的构造函数,该构造函数都会将其衰减复制到新线程可访问的存储中。 - 然后,新线程使用这些复制的参数调用可调用对象。
第一个片段复制一个指向缓冲区的指针。调用新线程的可调用对象然后将该指针转换为 a std::string
,但到那时缓冲区可能已经消失了。
当保证有效时,第二个片段在原始线程中执行转换。然后临时存储std::string
由std::thread
构造函数移动到中间存储中。
推荐阅读
- java - 限制对 RESTful 服务的呼出次数
- c# - 从 PFX 证书中删除密码
- jsf - 动作侦听器返回值未更新为输入文本值
- ios - 如何在选择行中的按钮时获取 UItableView 行的内容
- c# - 如何在 C# 中动态添加数组的索引值?
- python - 无法读取“https://source.developers.google.com”的用户名
- vba - 如何防止从破坏 HTML 的邮件中删除文本?
- ffmpeg - 迷失在将硬件加速的 ffmpeg 解码器转换为原始环回设备
- python - 如何使用 pandas tz_convert 转换为多个不同的时区
- java - 获取异常-java.lang.IllegalStateException:错误:文本块中不允许drawImage