15

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

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • By the as-if rule, if if their construction has no side effects and you never use them, I suppose that they don't need to be initialized at all! – Lightness Races in Orbit Apr 30 '13 at 12:55
  • 1
    AFAIK, no. They are initialized when first used/accessed. Only global statics will be initialized before main is called. – thecoshman Apr 30 '13 at 12:56
  • 1
    @Downvoter: Please explain your issue with the content of my question. Thanks. – Lightness Races in Orbit Apr 30 '13 at 13:04
  • 1
    yes, self answering question (especially when done well) are perfectly acceptable here. – thecoshman Apr 30 '13 at 13:09
  • 14
    "-1 Idiot, answering his own question. Next time you find some piece of interesting knowledge, keep it to yourself, will ya? No one wants you to share those tidbits of knowledge with the world. I'd rather remain ignorant than see you getting a few imaginary Internet dollar points." – R. Martinho Fernandes Apr 30 '13 at 13:10
  • @R.MartinhoFernandes: Trollolol – Lightness Races in Orbit Apr 30 '13 at 13:12
  • 5
    @thecoshman: Wrong, static class members behave in exactly the same way as global statics, which may or may not be initialized before `main` (but need to be initialized before the first use). Your comment applies to *function local* static variables, not to *class static members* – David Rodríguez - dribeas Apr 30 '13 at 13:14

2 Answers2

11

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. [..]

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    how come your question time and answer time are exactly the same? both are showing 12:55:04 in mine? :-) – Koushik Shetty Apr 30 '13 at 13:21
  • I find [c++11: 9.4.2/6] in my C++03 Standard at 9.4.2/7... new wording?? – dyp Apr 30 '13 at 13:27
  • 3
    @Koushik: It's a self-answered question and you can post the question and the answer with a single submit. – masoud Apr 30 '13 at 13:30
  • @DyP: Argh! You're right! I _completely_ missed that somehow! That's the road to the unambiguously correct answer if you'd like to go ahead and post it yourself... If not, I will edit mine, but the choice is yours. _[edit: actually, without C++11's 3.6.2/4, C++03 may **still** be ambiguous here]_ – Lightness Races in Orbit Apr 30 '13 at 13:34
  • There's also a "workaround" using static member functions (with local static variables), that does not have problems neither with point of initialization nor with init order. – dyp Apr 30 '13 at 13:34
  • Nah, you already have a very good answer. And you only need to change it slightly - no need for me to repeat the quotes in another order. – dyp Apr 30 '13 at 13:36
  • As far as [basic.scope] is concerned, I think it's even problematic to say "object of namespace scope" as only a _name_ has a scope (not an object). Certainly, the _name_ of a static data member does _not_ have namespace scope. But: "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." Therefore, IF there's a non-local object with dynamic init after the static data member, both should have the same init characteristic. – dyp Apr 30 '13 at 14:10
  • In your answer, the first line `I think no:` , is better if changed to `I say no:` :) – Barath Ravikumar Apr 30 '13 at 14:20
4

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;
}
dyp
  • 38,334
  • 13
  • 112
  • 177