Are static class members guaranteed to be initialized before `main` is called?

守給你的承諾、 提交于 2020-06-24 04:48:58

问题


Is there any guarantee that static class members are initialized before main is called?


回答1:


I think no:

[C++03: 3.6.2/3]: It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.


Hmm, really?

Well, arguably, "defined in namespace scope" is not quite the same thing as "an object of namespace scope":

[C++03: 9.4.2/2]: The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member's class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator. The initializer expression in the definition of a static data member is in the scope of its class (3.3.6).

However, it's the initializer that's in the class's scope; there's no mention of the static member itself having anything other than namespace scope (unless we mentally inject the word "lexically" everywhere).

There is this pleasing paragraph:

[C++03: 9.4.2/7]: Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).

However, unfortunately, the only further definition of the sequencing of main and static initialisation, with respect to "non-local objects", is the aforementioned [C++03: 3.6.2/3].


So what then?

I believe that the intent of this otherwise potentially ambiguous rule is clearly shown by the new wording in C++11, which resolves everything:

[C++11: 9.4.2/6]: Static data members are initialized and destroyed exactly like non-local variables (3.6.2, 3.6.3).

[C++11: 3.6.2/4]: It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. [..]




回答2:


C++03: In short, no guarantee

C++11: No guarantee, see Lightness' answer.

My interpretation/analysis of the C++03 statements:


Terminology: [basic.start.init]/1

Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization.


Order of initialization on non-local objects:

Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.

But it doesn't mention when "any other initialization" takes place, i.e. there's no guarantee it'll be before the first statement of main, even for zero-initialization.

Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.

But again, no guarantee.


Dynamic initialization

[basic.start.init]/3

It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.

But what is an "object of namespace scope"? I have not found any clear definition in the Standard. scope is actually a property of a name, not of an object. Therefore we could read this as "object defined in namespace scope" or "object introduced by a name of namespace scope". Note the reference "9.4" after dynamic initialization. It refers to "Static members", which can only mean static data members. So I'd say it means "object defined at namespace scope", as static data members are defined at namespace scope:

[class.static.data]/2

The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition.

Even if you don't agree on this interpretation, there's still [basic.start.init]/1

Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.

This clearly applies to static data members, which means that they cannot be initialized differently than objects introduced by names of namespace scope if there's such an object before the definition of the static data member. That is, if there was no guarantee at all on the dynamic initialization of static data members, the guarantees of any preceding object introduced by a name of namespace scope would apply - which are: none (it does not have to be initialized before the first statement of main).

If there's no such object preceding the definition of the static data member and you disagree on the interpretation - there would be no guarantee on the dynamic initialization of static data members at all.


Conclusion

So we only have a guarantee that dynamic initialization happens sometime (before any usage) plus an exception that initialization with side-effects must not be eliminated. Still, we have no guarantee that any kind of initialization of non-local objects is performed before the first statement of main.


Note: There are workarounds, like:

#include <iostream>

struct my_class
{
    static int& my_var()
    {
        static int i = 42;
        return i;
    }
};

int j = ++my_class::my_var();
int k = ++my_class::my_var();

int main()
{
    std::cout << j << " : " << k << std::endl;
}


来源:https://stackoverflow.com/questions/16300432/are-static-class-members-guaranteed-to-be-initialized-before-main-is-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!