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++中没有办法做到这一点,但是如果你对特定编译器内部结构有很好的工作知识,它可能是可以实现的。
#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
)来销毁它
它与指针的不同之处在于它已经预先分配了