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 &lt;&lt; "main loop" &lt;&lt; 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多线程 多线程传参详解

通过引用将值类型变量传递给静态方法线程安全吗?

C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数

C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数

线程安全的对象生命期管理

Java线程安全性中的对象发布和逸出