Destruction order of static objects in C++

2019-01-04 01:55发布

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条回答
放我归山
2楼-- · 2019-01-04 01:59

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.

查看更多
放荡不羁爱自由
3楼-- · 2019-01-04 02:12

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楼-- · 2019-01-04 02:13

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.

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

#pragma init_seg

for example, if you want file A's objects to be created before file B's:

File A.cpp:

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

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

In Watcom the segment is XI and variations on #pragma initialize can control construction:

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

...see documentation for more

查看更多
干净又极端
5楼-- · 2019-01-04 02:14

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

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

查看更多
The star\"
6楼-- · 2019-01-04 02:15

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.

查看更多
Animai°情兽
7楼-- · 2019-01-04 02:17

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:

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.

查看更多
登录 后发表回答