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

时间:2021-08-22 01:56:02

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?

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

9 个解决方案

#1


51  

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.

静态对象的破坏顺序与构造顺序相反。而且施工的顺序也很难控制。惟一可以确定的是,在同一个编译单元中定义的两个对象将按照定义的顺序构造。其他的都差不多是随机的。

#2


18  

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. 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 is necessary, it's very useful to know about it.

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

#3


11  

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.

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

#4


11  

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

静态对象是摧毁他们的反向顺序构造(如first-constructed对象被销毁最后),你可以控制序列构造静态对象,通过使用47项描述的技术,“确保全局对象初始化之前他们用“有效的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?

例如,以某种方式指定我希望某个对象最后被销毁,或者至少在另一个静态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 ...

我对迈耶斯项目47(4页)的解释如下。假设您全局是在头文件中定义的…

//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实例。

#5


4  

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. 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$XCB gets 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

…看到文档以了解更多

#6


3  

Read:
SO Initialization Order

读:初始化顺序

SO Solving the Order of Initialization Problem

求解初始化的顺序问题

#7


0  

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.

您总是可以使用单例来控制全局资源的构建/销毁顺序。

#8


0  

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.

它不会阻止您实际创建类的第二个实例,但如果您这样做,断言将失败。以我的经验来看,这是可行的。

#9


0  

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

通过使用静态std::可选的 而不是T,您可以有效地实现类似的功能,只需像对变量那样初始化它,使用indirection并通过分配std::nullopt(或者,对于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::可选 ,如果你没有std:: / std:::experimental:。

#1


51  

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.

静态对象的破坏顺序与构造顺序相反。而且施工的顺序也很难控制。惟一可以确定的是,在同一个编译单元中定义的两个对象将按照定义的顺序构造。其他的都差不多是随机的。

#2


18  

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. 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 is necessary, it's very useful to know about it.

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

#3


11  

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.

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

#4


11  

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

静态对象是摧毁他们的反向顺序构造(如first-constructed对象被销毁最后),你可以控制序列构造静态对象,通过使用47项描述的技术,“确保全局对象初始化之前他们用“有效的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?

例如,以某种方式指定我希望某个对象最后被销毁,或者至少在另一个静态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 ...

我对迈耶斯项目47(4页)的解释如下。假设您全局是在头文件中定义的…

//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实例。

#5


4  

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. 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$XCB gets 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

…看到文档以了解更多

#6


3  

Read:
SO Initialization Order

读:初始化顺序

SO Solving the Order of Initialization Problem

求解初始化的顺序问题

#7


0  

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.

您总是可以使用单例来控制全局资源的构建/销毁顺序。

#8


0  

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.

它不会阻止您实际创建类的第二个实例,但如果您这样做,断言将失败。以我的经验来看,这是可行的。

#9


0  

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

通过使用静态std::可选的 而不是T,您可以有效地实现类似的功能,只需像对变量那样初始化它,使用indirection并通过分配std::nullopt(或者,对于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::可选 ,如果你没有std:: / std:::experimental:。