#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
的析构函数中运行,那么thread
和text
的生存期是否应该持续同样长的时间?也就是说,当s超出main()
的范围时,它们都将超出范围?
答案 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
变量仍然可见,并且不会被删除。