使用 C++11 实现线程安全并使用临时对象通过引用传递

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)

类似问题

ζ--*_*ζ-- 7

根据标准释放临时对象,导致未定义行为。一个实现可以做任何事情,包括将对象的字节保存在堆栈内存中直到它们被覆盖,这允许您的代码(错误地)工作。

当我反汇编编译器(clang++ 9.0.1)生成的二进制文件时,我注意到当包含的块data结束时堆栈指针没有“回归” ,从而防止它在cout << "main loop" << endl;导致函数调用时被覆盖 。

此外,由于短字符串优化,实际的 ASCII“123”存储在std::string对象本身中,而不是存储在堆分配的缓冲区中。

标准草案说的情况如下:

6.6.4.3 自动存储时长

未明确声明为 static、thread_local 或 extern 的块范围变量具有自动存储持续时间。这些实体的存储一直持续到创建它们的块退出

实验上,如果我使字符串足够长以禁用短字符串优化,程序仍会静默运行,因为缓冲区中的字节碰巧在我的实验中保持完整。如果我启用 ASAN,我会收到一个正确的堆释放后使用警告,因为字节在字符串的生命周期结束时被释放,但通过非法使用指向现在被破坏的字符串的指针进行访问。