Geo*_*rge 2 c++ multithreading reference thread-safety
在阅读了Similar Question 中的答案后,我仍然在想为什么这个代码片段没有出现段错误。临时对象“数据”应该在离开作用域后被释放。但显然,“数据”并未公布。有人可以帮助我吗?谢谢
#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;
}
Run Code Online (Sandbox Code Playgroud)
根据标准释放临时对象,导致未定义行为。一个实现可以做任何事情,包括将对象的字节保存在堆栈内存中直到它们被覆盖,这允许您的代码(错误地)工作。
当我反汇编编译器(clang++ 9.0.1)生成的二进制文件时,我注意到当包含的块data结束时堆栈指针没有“回归” ,从而防止它在cout << "main loop" << endl;导致函数调用时被覆盖
。
此外,由于短字符串优化,实际的 ASCII“123”存储在std::string对象本身中,而不是存储在堆分配的缓冲区中。
该标准草案说的情况如下:
6.6.4.3 自动存储时长
未明确声明为 static、thread_local 或 extern 的块范围变量具有自动存储持续时间。这些实体的存储一直持续到创建它们的块退出。
实验上,如果我使字符串足够长以禁用短字符串优化,程序仍会静默运行,因为缓冲区中的字节碰巧在我的实验中保持完整。如果我启用 ASAN,我会收到一个正确的堆释放后使用警告,因为字节在字符串的生命周期结束时被释放,但通过非法使用指向现在被破坏的字符串的指针进行访问。