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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/469597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:30:30  来源:igfitidea点击:

Destruction order of static objects in C++

c++staticdestruction

提问by Gal Goldman

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?

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

回答by

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.

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

回答by Head Geek

The other answers to this insist that it can't be done. And they're right, according to the spec -- but there isa trick that will let you do it.

对此的其他答案坚持认为这是不可能的。他们是对的,依据规范-但有一招,可以让你做到这一点。

Create only a singlestatic 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, destroythem in whatever order you need to, in the constructor and destructor for StaticVariables. To make this completely transparent, you can create static references to the variables too, like so:

你可以按照你需要的任何顺序创建变量,更重要的是,在构造函数和析构函数中以你需要的任何顺序销毁它们StaticVariables。为了使这完全透明,您也可以创建对变量的静态引用,如下所示:

static Var1Type &var1(*svars.var1);

Voilà -- total control. :-) That said, this is extra work, and generally unnecessary. But when it isnecessary, it's very useful to know about it.

瞧——完全控制。:-) 也就是说,这是额外的工作,通常是不必要的。但是,当它必要的,这是非常有用的了解它。

回答by gimpf

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.

如果你真的需要一个特定的订单,你需要自己做这个。

回答by ChrisW

Static objects are destroyed in the reverse of the order in which they're constructed (e.g. 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. Assuming that you global is defined in a header file like this ...

我对 Meyers 的第 47 项(4 页长)的解释如下。假设您在这样的头文件中定义了 global ......

//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 (e.g. before your second global variable).

这样做的结果是,任何包含 GlobalA.h 的文件(例如,定义第二个全局变量的 GlobalB.cpp 源文件)都将定义 InitA 类的静态实例,该实例将在该类中的任何其他内容之前构造源文件(例如在您的第二个全局变量之前)。

This InitA class has a static reference counter. 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 类有一个静态引用计数器。当构造第一个 InitA 实例时,现在保证在构造 GlobalB 实例之前,InitA 构造函数可以做任何它必须做的事情来确保 globalA 实例被初始化。

回答by David Mott

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$XIsegment (for C type static init) or .CRT$XCsegment (for C++ type static init) The linker collects all declarations and merges them alphabetically. You can control the order in which static initialization occurs by declaring your objects in the proper segment using

在 Visual C++ 中,指向静态 init 函数的指针位于.CRT$XI段(对于 C 类型静态 init)或.CRT$XC段(对于 C++ 类型静态 init)中。链接器收集所有声明并按字母顺序合并它们。您可以通过使用在适当的段中声明您的对象来控制静态初始化发生的顺序

#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$XCBgets merged in before .CRT$XCC. When the CRT iterates through the static init function pointers it will encounter file A before file B.

.CRT$XCB在之前被合并.CRT$XCC。当 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

...查看文档了解更多信息

回答by Paolo.Bolzoni

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.

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

回答by lorro

You can effectively achieve similar functionality by having a static std::optional<T>instead of a 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).

您可以通过使用static std::optional<T>代替来有效地实现类似的功能T。只需像使用变量一样初始化它,使用间接并通过赋值std::nullopt(或者,对于 boost,boost::none)来销毁它。

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::.

boost::optional<T>如果您没有std::/ ,请使用std::experimental::

回答by Martin Cote

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.

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