C++ C++;11线程_局部析构函数行为

C++ C++;11线程_局部析构函数行为,c++,destructor,thread-local,C++,Destructor,Thread Local,我有以下情况:在标题“test.hpp”中定义: class ObjectA { public: ObjectA(); ~ObjectA(); static ObjectA & get_A(); }; class ObjectB { public: ~ObjectB(); static ObjectB & get_B(); void do_cleanup(); };

我有以下情况:在标题“test.hpp”中定义:

class ObjectA {
    public:
        ObjectA();
        ~ObjectA();
        static ObjectA & get_A();
};
class ObjectB {
    public:
        ~ObjectB();
        static ObjectB & get_B();
        void do_cleanup();
};
在单独的编译单元中,我实现了ObjectB:

#include "test.hpp"
#include <iostream>
ObjectB::~ObjectB() {
    std::cout<<"ObjectB dtor"<<std::endl;
}
ObjectB & ObjectB::get_B() {
    thread_local ObjectB b_instance;
    return b_instance;
}
void ObjectB::do_cleanup() {
    std::cout<<"Clearing up B garbage..."<<std::endl;
}
#包括“test.hpp”
#包括
ObjectB::~ObjectB(){

std::cout该规范说明了关于生命周期的两件事:

线程存储持续时间。对象的存储在线程开始时分配,在线程结束时释放。每个线程都有自己的对象实例

如果构造函数的完成或具有线程存储持续时间的对象的动态初始化在另一个对象的完成之前排序,则第二个对象的析构函数的完成在第一个对象的析构函数启动之前排序

现在回到你的代码

构造A,在构造函数中构造B。因此,B构造函数的完成发生在A构造函数完成之前。根据上面的说明,当线程即将退出时,它将首先销毁A,然后销毁B。根据规范的字母,您的代码是可以的


实际上,我不确定C++编译器是否实现了详细的规范。如果我写的代码,我不会用THeLexListObjor对象。这样,我就把B放在非静态字段A中。它比依赖语言标准的细微差别更简单和更可靠。r支持线程局部变量?并不是所有编译器都达到了标准的这一部分。但是顺序看起来是正确的。在A的构造函数中使用B可以确保它在A之前处于活动状态。因此A将首先被分解。这将调用B清理,然后B将被分解。这应该都发生在同一线程的范围内。注意:Compiles和ru使用
LLVM版本8.0.0
OK,感谢您的澄清。我遇到了thread_本地版本的静态对象销毁地狱。(两个编译单元的静态对象被销毁的未定义顺序)
#include "test.hpp"
#include <iostream>
ObjectA::ObjectA() {
    ObjectB::get_B(); <--dummy call to initialize thread_local ObjectB;
}
ObjectA::~ObjectA() {
     std::cout<<"ObjectA dtor"<<std::endl;
     ObjectB::get_B().do_cleanup(); // <-- is this undefined behaviour??
}
ObjectA & ObjectA::get_A() {
     thread_local ObjectA a_instance;
     return a_instance;
}
#include <thread>
#include "test.hpp"
int main() {
    std::thread check([](){
    ObjectA::get_A(); //<--dummy call just to initialize thread_local object.
    });
    check.join();
    return 0;
}