user2953119
user2953119

Reputation:

Is order of static initialization implementation defined?

Dynamic initialization can be ordered or unordered:

Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered.

This does not say anything about order of static initialization. Is it true that order of static initialization is implementation defined?

Upvotes: 4

Views: 662

Answers (4)

T.C.
T.C.

Reputation: 137394

Static initialization does not mean "initialization of variables with static storage duration". It is a much more limited term and is defined in §3.6.2 [basic.start.init]/p2.

Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

Constant initialization is defined in the same paragraph and basically involves initialization to compile-time constants.

Because static initialization involves initialization to compile-time constants and is guaranteed to occur before any dynamic initialization takes place, the order doesn't really matter. (In practice, for objects of static storage duration, the initial values are probably placed in the data segment (bss segment for zero-initialization) of the compiled executable and loaded by the operating system directly at program start, so speaking of an "order" doesn't make much sense.) Anything for which the "static initialization fiasco" can arise actually involves dynamic initialization.

Upvotes: 4

Adriano Repetti
Adriano Repetti

Reputation: 67148

Is it true that order of Static Initialization is implementation defined?

I see pretty confused answers so let me summarize: NO, STATIC INITIALIZATION ORDER IS NOT IMPLEMENTATION DEFINED.

Let's see why and in which cases. According to your quote let me assume you're asking about (static or dynamic) initialization of non-local variables static storage duration.

C++ standard §9.4.2 (paragraph 6) says:

Static data members are initialized and destroyed exactly like non-local variables.

Then according to §3.6.2 and §3.7.1 no, [order] within a compilation unit is not implementation defined but it always follows declaration order (as described in §6.7 paragraph 4):

Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

Rules for static and dynamic initialization are the same and they're described in same paragraph, the only (remarkable) difference between static and dynamic initialization is ordering, static initialization will always occurs before dynamic initialization and dynamic initialization may be unordered.

Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

How static initialized non-local variables are initialized is described in paragraphs 1 and 2 from §3.6.2:

Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place. Constant initialization is performed...[omitted]

According to comments I need to clarify this point: a non-local static variable may have thread storage duration specifier thread_local (then it'll behave like a static variable from user POV nut they also be combined). It's still eligible for static initialization (then ordered and then it must obey to above rule) but initialization can't be performed simply loading data segment from disk. Code must be executed (TlsAlloc on Windows) but from standard POV it's still a static initialized expression (first zero-initialized and then with constant initialization). Let's see a very fictional example:

thread_local unsigned int _value = 1;

Now let's try to imagine how compiler may implement that. We can start with something known and imagine a behavior similar to boost::thread_specific_ptr. Implementation on Windows (but it's pretty similar on Windows too) will need to call TlsAlloc when thread is initialized and TlsFree when thread is finished. You'll access variable normally but probably it'll implemented as a pointer with an offset from memory allocated by TlsAlloc. The only thing that will come from executable file on disk is initial value (and again it's just an implementation detail who you shouldn't care). Initial value (as described before) will be 0 (for unsigned int). Given all this code, these function calls and so many details...probably it's still eligible to be considered constant initialization because requirements imposed by standard are fulfilled then compiler should (may) respect them. It means it may be static initialized. To summarize:

  • Standard says that static initialized variables will respect declaration order.
  • Standard says when variables are dynamically initialized and when statically initialized.
  • Standard does not say where that values should come from at run-time.
  • Standard does not say how implementation should initialize them.

Of course inside a single function same rule apply but declaration should be replaced with usage (§6.7 ) but this isn't your question.

Order for different compilation unit is not granted and it's implementation defined (but there are techniques to make this order arbitrary then predictable: Nifty Counter and variables aggregation, for example).

Upvotes: 2

Mohit Jain
Mohit Jain

Reputation: 30489

In general about Dynamic initialization of a variable with static storage

  • static objects in function scope are initialized at first use (just before access).
  • In file scope(non-local scope, before main), static objects of a file are initialized in order of definition
  • For file scope static objects lying across the files(compilation units), order is unspecified.

If you want more details read below:

Quoting from cppreference

Static variables declared at block scope are initialized the first time control passes through their declaration (unless their initialization is zero- or constant-initialization, which can be performed before the block is first entered). On all further calls, the declaration is skipped.

Quoting from 6.7 Declaration statement stmt.dcl (n3690)

The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered.

Quoting From 3.6.2 basic.start.init (n3690)

Other non-local variables with static storage duration have ordered initialization. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit.

You may also want to read this page from parashift.

About static (const) initialization, it happens as early as possible, most possibly during compile time. All static initialization completes before dynamic initialization.

Upvotes: 2

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42929

  • Within the same compilation unit the order is well defined (i.e., it follows the order of definition).

  • Order is unspecified across different compilation units. This is due to the fact that this issue is solved in linker level and not compiler level.

  • This ambiguity can case the known static initialization fiasco.

Upvotes: 0

Related Questions