C++ C+中静态对象的销毁顺序+;

C++ C+中静态对象的销毁顺序+;,c++,static,destruction,C++,Static,Destruction,我可以控制静态对象被销毁的顺序吗? 有没有办法执行我想要的命令?例如,以某种方式指定我希望某个对象最后销毁,或者至少在另一个静态对象之后销毁?不,您不能。您永远不应该依赖于其他静态对象的构造/破坏 您始终可以使用单例来控制全局资源的构造/销毁顺序。静态对象按与构造相反的顺序销毁。施工顺序很难控制。唯一可以确定的是,在同一个编译单元中定义的两个对象将按照定义的顺序构造。其他事情或多或少都是随机的。简短回答:一般来说,没有 回答稍微长一点:对于单个转换单元中的全局静态对象,初始化顺序是从上到下,销毁

我可以控制静态对象被销毁的顺序吗?
有没有办法执行我想要的命令?例如,以某种方式指定我希望某个对象最后销毁,或者至少在另一个静态对象之后销毁?

不,您不能。您永远不应该依赖于其他静态对象的构造/破坏


您始终可以使用单例来控制全局资源的构造/销毁顺序。

静态对象按与构造相反的顺序销毁。施工顺序很难控制。唯一可以确定的是,在同一个编译单元中定义的两个对象将按照定义的顺序构造。其他事情或多或少都是随机的。

简短回答:一般来说,没有

回答稍微长一点:对于单个转换单元中的全局静态对象,初始化顺序是从上到下,销毁顺序正好相反。几个翻译单元之间的顺序未定义


如果你真的需要一个特定的顺序,你需要自己来完成。

静态对象的销毁顺序与构建顺序相反(例如,第一个构建的对象最后销毁),你可以使用第47项中描述的技术控制静态对象的构建顺序,“<强>确保全局对象在使用之前被初始化为< /强>”在迈尔斯的《有效C++》中。

例如,以某种方式指定我希望某个对象最后销毁,或者至少在另一个静态对象之后销毁

确保它是在其他静态对象之前构造的


如何控制构造顺序?不是所有的静态都在同一个dll中

为了简单起见,我将忽略它们不在同一个DLL中这一事实

我对Meyers的第47项(4页长)的解释如下

//GlobalA.h
extern GlobalA globalA; //declare a global
//GlobalA.h
extern GlobalA globalA; //declare a global
class InitA
{
  static int refCount;
public:
  InitA();
  ~InitA();
};
static InitA initA;
…向包含文件添加一些代码,如下所示

//GlobalA.h
extern GlobalA globalA; //declare a global
//GlobalA.h
extern GlobalA globalA; //declare a global
class InitA
{
  static int refCount;
public:
  InitA();
  ~InitA();
};
static InitA initA;
这样做的效果是,任何包含GlobalA.h的文件(例如,定义第二个全局变量的GlobalB.cpp源文件)都将定义InitA类的静态实例,该实例将在该源文件中的任何其他文件(例如,在第二个全局变量之前)之前构造


这个InitA类有一个静态引用计数器。当构造第一个InitA实例时(现在保证在构造GlobalB实例之前),InitA构造函数可以做任何它必须做的事情来确保globalA实例被初始化。

对此的其他答案坚持认为它不能做。它们是是的,根据规范——但有一个技巧可以让你做到这一点

只创建一个类或结构的静态变量,该类或结构包含通常生成静态变量的所有其他内容,如下所示:

class StaticVariables {
    public:
    StaticVariables(): pvar1(new Var1Type), pvar2(new Var2Type) { };
    ~StaticVariables();

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;
static Var1Type &var1(*svars.var1);
您可以按照需要的顺序创建变量,更重要的是,可以按照需要的顺序在
StaticVariables
的构造函数和析构函数中销毁变量。要使其完全透明,您也可以创建变量的静态引用,如下所示:

class StaticVariables {
    public:
    StaticVariables(): pvar1(new Var1Type), pvar2(new Var2Type) { };
    ~StaticVariables();

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;
static Var1Type &var1(*svars.var1);
瞧——完全控制。:-)也就是说,这是额外的工作,通常是不必要的。但在必要的时候,了解它是非常有用的。

阅读:


在标准C++中没有办法做到这一点,但是如果你对特定编译器内部结构有很好的工作知识,它可能是可以实现的。 > CRT$XI/CUT>段(对于C型静态init)或 > CRT $XC段(对于C++席静态init)链接器收集所有声明并按字母顺序合并它们。通过使用

#pragma init_seg
例如,如果要在文件B之前创建文件A的对象,请执行以下操作:

文件A.cpp:

#pragma init_seg(".CRT$XCB")
class A{}A;
文件B.cpp:

#pragma init_seg(".CRT$XCC")
class B{}B;
.CRT$XCB
.CRT$XCC
之前被合并。当CRT迭代通过静态init函数指针时,它将在文件B之前遇到文件A

在WATCOM中,段是XI,而席语用初始化的变化可以控制结构:

#pragma initialize before library
#pragma initialize after library
#pragma initialize before user

…有关详细信息,请参阅文档是否确实需要在
main
之前初始化变量

如果您不知道,您可以使用一个简单的习惯用法轻松地实际控制构造和破坏的顺序,请参见此处:

#include <cassert>

class single {
    static single* instance;

public:
    static single& get_instance() {
        assert(instance != 0);
        return *instance;
    }

    single()
    // :  normal constructor here
    {
        assert(instance == 0);
        instance = this;
    }

    ~single() {
        // normal destructor here
        instance = 0;
    }
};
single* single::instance = 0;

int real_main(int argc, char** argv) {
    //real program here...

    //everywhere you need
    single::get_instance();
    return 0;
}

int main(int argc, char** argv) {
    single a;
    // other classes made with the same pattern
    // since they are auto variables the order of construction
    // and destruction is well defined.
    return real_main(argc, argv);
}
#包括
单班{
静态单*实例;
公众:
静态单实例&get_实例(){
断言(实例!=0);
返回*实例;
}
单个()
//:此处为普通构造函数
{
断言(实例==0);
实例=此;
}
~single(){
//这里是正常的析构函数
实例=0;
}
};
single*single::instance=0;
int real_main(int argc,char**argv){
//真正的程序在这里。。。
//你需要的任何地方
single::get_instance();
返回0;
}
int main(int argc,字符**argv){
单a;
//用相同图案制作的其他类
//因为它们是自动变量,所以结构的顺序
//破坏的定义是明确的。
返回实数_main(argc、argv);
}

它不会阻止您实际尝试创建该类的第二个实例,但如果您这样做,断言将失败。根据我的经验,它工作得很好。

通过使用
静态std::optional
而不是
T
,您可以有效地实现类似的功能。只需像使用变量一样初始化它,然后使用间接通过分配
std::nullopt
(或者,对于boost,
boost::none
)来销毁它

它与指针的不同之处在于它已经预先分配了