简体   繁体   English

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

[英]Destruction order of static objects in C++

Can I control the order static objects are being destructed? 我可以控制销毁静态对象的顺序吗? Is there any way to enforce my desired order? 有什么方法可以执行我想要的命令? For example to specify in some way that I would like a certain object to be destroyed last, or at least after another static object? 例如,以某种方式指定我希望某个对象最后被破坏,或者至少在另一个静态对象之后被破坏?

The static objects are destructed in the reverse order of construction. 静态对象以相反的顺序破坏。 And the order of construction is very hard to control. 而且施工顺序很难控制。 The only thing you can be sure of is that two objects defined in the same compilation unit will be constructed in the order of definition. 您唯一可以确定的是,将按定义顺序构造在同一编译单元中定义的两个对象。 Anything else is more or less random. 其他任何事物或多或少都是随机的。

The other answers to this insist that it can't be done. 对此的其他答案坚持认为它无法完成。 And they're right, according to the spec -- but there is a trick that will let you do it. 他们是对的,依据规范-但一个小窍门,可以让你做到这一点。

Create only a single static variable, of a class or struct that contains all the other things you would normally make static variables, like so: 创建只有一个静态变量,它包含了所有其他的事情,你通常会做静态变量,像这样一类或结构的,:

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

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;

You can create the variables in whatever order you need to, and more importantly, destroy them in whatever order you need to, in the constructor and destructor for StaticVariables . 您可以创建你需要的任何顺序变量,更重要的是, 摧毁他们在任何你需要的才能,在构造函数和析构函数StaticVariables To make this completely transparent, you can create static references to the variables too, like so: 为了使其完全透明,您也可以创建对变量的静态引用,如下所示:

static Var1Type &var1(*svars.var1);

Voilà -- total control. Voilà-完全控制。 :-) That said, this is extra work, and generally unnecessary. :-)也就是说,这是额外的工作,通常是不必要的。 But when it is necessary, it's very useful to know about it. 但是,当必要时,了解它非常有用。

Static objects are destroyed in the reverse of the order in which they're constructed (eg the first-constructed object is destroyed last), and you can control the sequence in which static objects are constructed, by using the technique described in Item 47, " Ensure that global objects are initialized before they're used " in Meyers' book Effective C++ . 静态对象的破坏顺序与生成它们的顺序相反(例如,第一个破坏的对象最后被破坏),您可以使用第47条中所述的技术来控制静态对象的生成顺序,在Meyers的书《 Effective C ++ 》中“ 确保在使用全局对象之前对其进行了初始化 ”。

For example to specify in some way that I would like a certain object to be destroyed last, or at least after another static onject? 例如,以某种方式指定我希望某个对象最后被破坏,或者至少在另一个静态注入之后被破坏?

Ensure that it's constructed before the other static object. 确保在其他静态对象之前构造它。

How can I control the construction order? 如何控制施工顺序? not all of the statics are in the same dll. 并非所有的静态函数都在同一个dll中。

I'll ignore (for simplicity) the fact that they're not in the same DLL. 为了简单起见,我将忽略它们不在同一个DLL中的事实。

My paraphrase of Meyers' item 47 (which is 4 pages long) is as follows. 我对迈耶斯项目47(长4页)的解释如下。 Assuming that you global is defined in a header file like this ... 假设您在这样的头文件中定义了全局变量...

//GlobalA.h
extern GlobalA globalA; //declare a global

... add some code to that include file like this ... ...向这样的包含文件添加一些代码...

//GlobalA.h
extern GlobalA globalA; //declare a global
class InitA
{
  static int refCount;
public:
  InitA();
  ~InitA();
};
static InitA initA;

The effect of this will be that any file which includes GlobalA.h (for example, your GlobalB.cpp source file which defines your second global variable) will define a static instance of the InitA class, which will be constructed before anything else in that source file (eg before your second global variable). 这样做的结果是,任何包含GlobalA.h的文件(例如,定义了第二个全局变量的GlobalB.cpp源文件)都将定义InitA类的静态实例,该实例将在该实例中的其他任何对象之前进行构造源文件(例如,在第二个全局变量之前)。

This InitA class has a static reference counter. 该InitA类具有静态引用计数器。 When the first InitA instance is constructed, which is now guaranteed to be before your GlobalB instance is constructed, the InitA constructor can do whatever it has to do to ensure that the globalA instance is initialized. 当构造第一个InitA实例时(现在可以保证在构造GlobalB实例之前),InitA构造函数可以执行其必须做的一切以确保初始化globalA实例。

Short answer: In general, no. 简短的回答:一般而言,不会。

Slightly longer answer: For global static objects in a single translation-unit the initialization order is top to bottom, the destruction order is exactly reverse. 稍长的答案:对于单个转换单元中的全局静态对象,初始化顺序从上到下,销毁顺序恰好相反。 The order between several translation-units is undefined. 多个翻译单元之间的顺序是不确定的。

If you really need a specific order, you need to make this up yourself. 如果您确实需要特定的订单,则需要自己进行调整。

Theres no way to do it in standard C++ but if you have a good working knowledge of your specific compiler internals it can probably be achieved. 在标准C ++中无法做到这一点,但是如果您对特定的编译器内部有很好的了解,则可以实现。

In Visual C++ the pointers to the static init functions are located in the .CRT$XI segment (for C type static init) or .CRT$XC segment (for C++ type static init) The linker collects all declarations and merges them alphabetically. 在Visual C ++中,指向静态init函数的指针位于.CRT$XI段(对于C类型的静态init)或.CRT$XC段(对于C ++类型的静态init)。链接器收集所有声明并将它们按字母顺序合并。 You can control the order in which static initialization occurs by declaring your objects in the proper segment using 通过使用以下方法在适当的段中声明对象,可以控制静态初始化发生的顺序:

#pragma init_seg

for example, if you want file A's objects to be created before file B's: 例如,如果要在文件B之前创建文件A的对象:

File A.cpp: 文件A.cpp:

#pragma init_seg(".CRT$XCB")
class A{}A;

File B.cpp: 文件B.cpp:

#pragma init_seg(".CRT$XCC")
class B{}B;

.CRT$XCB gets merged in before .CRT$XCC . .CRT$XCB.CRT$XCC之前合并。 When the CRT iterates through the static init function pointers it will encounter file A before file B. 当CRT遍历静态init函数指针时,它将在文件B之前遇到文件A。

In Watcom the segment is XI and variations on #pragma initialize can control construction: 在Watcom中,该段是XI,#pragma initialize的变体可以控制构造:

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

...see documentation for more ...有关更多信息,请参见文档

Do you really need the variable to be initialized before main ? 您真的需要在main之前初始化变量吗?

If you don't you can use a simple idiom to actually control the order of construction and destruction with ease, see here: 如果您不这样做,则可以使用简单的习惯用法轻松地实际控制构造和破坏的顺序,请参见此处:

#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);
}

It does not STOP you to actually try to create a second instance of the class, but if you do the assertion will fail. 它并不能阻止您实际尝试创建该类的第二个实例,但是如果您这样做,则断言将失败。 In my experience it works fine. 以我的经验,它可以正常工作。

You can effectively achieve similar functionality by having a static std::optional<T> instead of a T . 可以通过具有有效地实现类似的功能static std::optional<T>代替T Just initialize it as you'd do with a variable, use with indirection and destroy it by assigning std::nullopt (or, for boost, boost::none ). 只需像对变量一样进行初始化,与间接调用一起使用,并通过分配std::nullopt (或者对于boost,使用boost::none )销毁它std::nullopt

It's different from having a pointer in that it has preallocated memory, which is I guess what you want. 它与具有指针的不同之处在于它具有预分配的内存,我想这就是您想要的。 Therefore, if you destroy it & (perhaps much later) recreate it, your object will have the same address (which you can keep) and you don't pay the cost of dynamic allocation/deallocation at that time. 因此,如果销毁它并(可能以后再重新创建)它,则对象将具有相同的地址(可以保留),并且此时您无需支付动态分配/取消分配的费用。

Use boost::optional<T> if you don't have std:: / std::experimental:: . 如果您没有std:: / std::experimental::请使用boost::optional<T>

No, you can't. 不,你不能。 You should never rely on the other of construction/destruction of static objects. 您永远不应依赖于静态对象的构造/破坏。

You can always use a singleton to control the order of construction/destruction of your global resources. 您始终可以使用单例来控制构建/销毁全局资源的顺序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM