在std :: thread中运行时,C ++成员变量的寿命是多少?

时间:2019-12-28 07:31:50

标签: c++ c++11 lifetime stdthread

#include <iostream>
#include <string>
#include <thread>

using namespace std;

struct safe_thread : public thread
{
    using thread::thread;

    safe_thread& operator=(safe_thread&&) = default;

    ~safe_thread()
    {
        if (joinable())
        {
            join();
        }
    }
};

struct s
{
    safe_thread t;
    std::string text = "for whatever reason, this text will get corrupted";

    s() noexcept
    {
        std::cout << text << '\n'; // it works in constructor as expected
        t = safe_thread{ [this]
                         { long_task(); }};
    }

    void long_task()
    {
        for (int i = 0; i < 500; ++i)
        {
            std::cout << text << '\n'; // the text gets corrupted in here
        }
    }
};

int main()
{
    s s;
}

在上面的代码中,text变量将在构造函数中正确打印。但是,在单独线程中运行的long_task()函数中,文本已损坏(在另一台计算机上完全崩溃)。怎么了如果safe_thread的析构函数将在struct s的析构函数中运行,那么threadtext的生存期是否应该持续同样长的时间?也就是说,当s超出main()的范围时,它们都将超出范围?

1 个答案:

答案 0 :(得分:10)

您的问题按s类中声明成员变量的顺序进行。

int main()
{
    s s;
    // here is called dtor of S
}

调用析构函数时,数据成员按照其声明的相反顺序销毁。你有:

safe_thread t; // [2]
std::string text = "for whatever reason, this text will get corrupted"; // [1]

因此,在销毁第一个字符串[1]之后,将调用[2]线程的析构函数,并且在此调用期间,您的程序将加入。但是随后它正在访问已破坏的text变量。是UB。

将顺序更改为:

std::string text = "for whatever reason, this text will get corrupted";
safe_thread t;

通过这种方法,在加入t时,text变量仍然可见,并且不会被删除。