4

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?

Wolf
  • 9,679
  • 7
  • 62
  • 108
  • 1
    static in function scope initialize at first use. In file scope(before main), static of a file initialize top to bottom. For static lying across the files, order is unspecified. – Mohit Jain Jul 02 '14 at 12:39
  • 1
    @MohitJain Please, provide a reference to the Standard describing that. –  Jul 02 '14 at 12:42
  • I added it as detailed answer. – Mohit Jain Jul 02 '14 at 13:14
  • You are confusing *static initialization* and *initialization of objects of static storage duration*. They are not the same thing. – T.C. Jul 02 '14 at 13:20
  • 1
    Static initialization consists of zero-initialization and constant initialization. I don't think you can get order dependency for either one. – dyp Jul 02 '14 at 13:46

4 Answers4

4

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • You're right about wrong terminology in question but according to OP's quote he is talking about _non-local variable with static storage_. Then IMO static initialization [of non static variables] isn't what he is asking for (and rules for static and non static are different). – Adriano Repetti Jul 02 '14 at 15:13
  • @AdrianoRepetti He's quoting from a section entitled "Initialization of non-local variables". All the sequencing rules related to dynamic initialization of these variables appear *immediately* after the sentence he quoted, and I don't consider it necessary to repeat it. – T.C. Jul 02 '14 at 15:19
  • No, I do not agree with your last paragraph. According to §3.6.2 paragraphs 1 & 2. – Adriano Repetti Jul 02 '14 at 15:23
  • @AdrianoRepetti What do you disagree with? – T.C. Jul 02 '14 at 15:27
  • When you say "_the order doesn't really matter. (In practice, the initial values are probably placed in the data segment_". According to text **before** his quote (3.6.2p2) this isn't true. Static initialization is a two step process and it may involve **object creation** (moreover interacting with **thread storage**). That may cause a lot of code to be executed (also with calls to OS). Static initialization isn't only for constant expressions of primitive types. – Adriano Repetti Jul 02 '14 at 15:37
  • @AdrianoRepetti The only case where object creation could happen for static initialization is a `constexpr` constructor with compile-time constants for everything, where the compiler can execute the constructor at compile-time. I'll qualify the parenthetical note to static storage duration, though. – T.C. Jul 02 '14 at 15:39
  • No, it's not required to be done at compile time. It is, sometimes, but it's an implementation detail (for example even a const expression with thread storage may involve a function call to OS API). That's why standard explicitly says first they should be zero-initialized and then constant initialization may be performed. – Adriano Repetti Jul 02 '14 at 15:47
  • @AdrianoRepetti How exactly could a function call to OS API appear in a constant expression? §5.19/p2 of the standard: "A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [...] an invocation of a function other than a `constexpr` constructor for a literal class or a `constexpr` function". An OS API is by definition not `constexpr`. – T.C. Jul 02 '14 at 15:52
  • Compiler will **zero-initialize variables then it'll emit code** for constant initialization using OS calls for thread storage. You won't ever see that call but they must be performed (if required) **exactly in the order variables are declared**. It doesn't mean compiler will always do it. Probably (but I can't see any reference so it's just unspecified) only zero-initialization can be done like you say. – Adriano Repetti Jul 02 '14 at 15:55
  • For example (on Windows) memory for non-local variables with thread storage must be explicitly allocated with `TlsAlloc` and you perform write through a `TlsSetValue`. It's done through code (emitted by compiler) not a simply raw data segment load. – Adriano Repetti Jul 02 '14 at 15:58
  • @AdrianoRepetti Which part of the standard says that static initialization of objects of thread storage duration must be performed in order of declaration? And I already qualified the data segment note to static storage duration. – T.C. Jul 02 '14 at 15:59
  • Same paragraph i quoted before: _"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."_. It doesn't matter if there is thread storage or not, that's what required. BUT. When thread storage is also present then that requirement must be fulfilled too. – Adriano Repetti Jul 02 '14 at 16:03
  • @AdrianoRepetti "Other non-local variables with static storage duration" by definition excludes "non-local variables of thread storage duration". I would be very surprised if they specify an order for static initialization, because the whole point of the *constant initialization* rules is to ensure that the initial value is a compile-time constant and hence has no dependency on initialization order. – T.C. Jul 02 '14 at 16:05
  • We're confusing static variables with static duration. A thread storage variable may (and often it will) be a static variable. Thread storage variables are eligible for constant initialization (see same paragraph) then performed during static initialization. What's not clear (to me) is if expression for temporaries (§8.5) has to be constant too. – Adriano Repetti Jul 02 '14 at 16:25
  • One clarification to your answer: You said that initial value had been placed in data segments (bss segment for zero initialization). Which part of Standard defines data segments? –  Jul 02 '14 at 16:49
  • @DmitryFucintv It's an implementation detail (as in, "this is usually what happens in a real program on a real computer"), not defined in the standard (which defines a C++ abstract machine). – T.C. Jul 02 '14 at 17:15
  • @T.C. Is there any documentation for that? Is it depends on OS? I'm using linux mint 14. If you know, please suggest me any documentation about it. Thanks. –  Jul 02 '14 at 17:21
  • 1
    @DmitryFucintv You can check out the specification of the executable file format for the platform. For Linux, it's ELF. – T.C. Jul 02 '14 at 17:33
  • @DmitryFucintv it may happen, it may not (you can have fun with ELF for hours) but the point is that whole answer IMO is **not correct** because starts with a bad assertion (static initialization = only code dumped for exe, order doesn't matters and it doesn't apply). Actually standard isn't undefined here, order _may_ matters and it's well-defined. Moreover data may be result of a run-time operation... – Adriano Repetti Jul 02 '14 at 20:16
  • @AdrianoRepetti You still haven't shown how static initialization with the definition given in the standard could *possibly* be order dependent. – T.C. Jul 02 '14 at 20:29
  • I updated my answer with an example (I should really improve my English if I can't explain this). Simply this line `thread_local int value = 1;` will break your assumption. The point is that standard DOES NOT SAY that statically initialized variables are unordered. They fall in the general case of ordered one ("...others..."). Try to imagine to implement what compiler does, how can you do it loading raw data from exe?! – Adriano Repetti Jul 02 '14 at 20:33
  • @AdrianoRepetti And how, exactly, is that order dependent? – T.C. Jul 02 '14 at 21:01
  • AFAIK most of times [declaration] order does not really matter to us unless (with compiler specific extensions) they're mapped to specific I/O addresses. Also declaration order ensures you can reference previously declared variables, this is more important for more complex dynamic initialization but there isn't any reason standard had to be more ambiguous about static initialization. – Adriano Repetti Jul 03 '14 at 06:40
2

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.

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • Thanks. But I'm looking for strictly normative reference from final working draft (I'm using N3797). I can find initialization order for dynamic storage duration (It is specified in 3.6.2/2), but not for static initialization. –  Jul 02 '14 at 12:53
  • @DmitryFucintv I should have added this while answering. Anyways, corrected. – Mohit Jain Jul 02 '14 at 13:00
  • By file scope static variables, I meant non-local static variabled. These are initialized before `main` even if not used anywhere. – Mohit Jain Jul 02 '14 at 13:11
  • @MohitJain no, if initialized before main or after it started is implementation defined. They're always initialized (even before first usage) if initializer has side effects. – Adriano Repetti Jul 02 '14 at 13:23
  • 1
    @MohitJain By file scope static variables, you probably mean namespace scope (although class scope static variables behave in much the same way). – James Kanze Jul 02 '14 at 13:29
  • @AdrianoRepetti Thank you for correcting me. Do you mean a conforming implementation may choose not to initialize non-local static if they are not used at all and initializer does not have a side effect? Also is it possible that side effect is observed after the main code has started executing? – Mohit Jain Jul 02 '14 at 13:38
  • @JamesKanze Yes I mean static object not within a block. They may lie in some namespace, or default namespace. – Mohit Jain Jul 02 '14 at 13:40
  • @MohitJain if I read it well yes, initialization (with exceptions and rules stated in 3.6.2) is performed only before first use (let me assume if without special storage specifiers). – Adriano Repetti Jul 02 '14 at 13:43
  • @AdrianoRepetti Doesn't it conflict with *A non-local variable with static storage duration having initialization with side-effects must be initialized even if it is not odr-used (3.2, 3.7.1).*. Or I am missing something? – Mohit Jain Jul 02 '14 at 13:46
  • 1
    @MohitJain key sentence is "with side-effects" (_...They're always initialized (even before first usage) if initializer has side effects..._). If (and only if) without side-effects implementation may (according to 3.6.2) postpone their initialization when they're first used. If an initialization without side-effects is never used in code then yes...compiler may even remove it (as optimization). – Adriano Repetti Jul 02 '14 at 13:52
  • @AdrianoRepetti Thank you. I got your point after reading again. – Mohit Jain Jul 02 '14 at 14:00
2

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

Community
  • 1
  • 1
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • **§3.6.2** and **§3.7.1** refer to non-local static variables, while **§6.7** refers to block-scope static variables. These are not the same thing and hence they have different rules. Specifically, an application is *permitted* to use the rules in **§3.6.2** for early initialization of block-scope static variables, but may also defer until control passes through its declaration. – Edward Jul 02 '14 at 13:34
  • @Edward yes, 3.6.2 and 3.7.1 are for non local (for example a compilation unit but as referenced a static member too as per 9.4.2). I didn't see _permitted_ anyway general rules for block-scope are in 6.7 (and links). – Adriano Repetti Jul 02 '14 at 13:38
0
  • 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.

101010
  • 41,839
  • 11
  • 94
  • 168