C++11 的线程安全和临时对象的引用传递
Posted
技术标签:
【中文标题】C++11 的线程安全和临时对象的引用传递【英文标题】:Thread-safety with C++11 and passing by reference with temporary object 【发布时间】:2020-04-24 01:21:21 【问题描述】:在阅读Similar Question 中的答案后,我仍然想知道为什么这段代码 sn-p 不会出现段错误。临时对象“数据”应在离开范围后释放。但显然,“数据”并未公布。 有人可以帮助我吗? 谢谢
#include <iostream>
#include <string>
#include <thread>
using namespace std;
void thfunc(string &data)
for (;;)
cout << data << endl;
int main()
string data = "123";
std::thread th1(thfunc, std::ref(data));
th1.detach();
for (;;)
cout << "main loop" << endl;
return 0;
Similar Question
【问题讨论】:
把你的字符串变成 17 个字符,看看会发生什么。 @JohnFilleau sso?当它开始时很有趣。:) 【参考方案1】:临时对象按标准释放,导致未定义的行为。一个实现可以做任何事情,包括将对象的字节保存在堆栈内存中直到它们被覆盖,这允许您的代码(不正确地)工作。
当我反汇编编译器 (clang++ 9.0.1) 生成的二进制文件时,我注意到当包含 data
的块结束时堆栈指针没有“回归”,从而防止它在
cout << "main loop" << endl;
导致函数调用。
此外,由于short string optimization,实际的ASCII“123”存储在std::string
对象本身中,而不是在堆分配的缓冲区中。
draft standard 表示以下内容:
6.6.4.3 自动存储时长
未显式声明为 static、thread_local 或 extern 的块范围变量具有自动存储持续时间。这些实体的存储将持续直到创建它们的块退出。
在实验中,如果我使字符串足够长以禁用短字符串优化,程序仍然静默工作,因为缓冲区中的字节碰巧在我的实验中保持完整。如果我启用 ASAN,我会收到正确的 heap use-after-free 警告,因为字节在字符串的生命周期结束时被释放,但通过非法使用指向现已销毁的字符串的指针进行访问。
【讨论】:
@TedLyngmo 从语言律师的角度来看,我正在阅读规范以 100% 确定,但对于这个例子(data
的范围用大括号缩小)应该是不行。
@TedLyngmo 据我所知,延长寿命在这里没有用。它only applies 当我们处理分配对临时的引用(例如返回值)时。在这里,我们在某个时间点有一个非临时性的超出范围。
@TedLyngmo 没问题!
我认为您在更新的答案中涵盖了我所有的问题。太好了!以上是关于C++11 的线程安全和临时对象的引用传递的主要内容,如果未能解决你的问题,请参考以下文章
C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数