How lazy can C++ global initialization be?
Asked Answered
P

4

10

I'm used to thinking of all initialization of globals/static-class-members as happening before the first line of main(). But I recently read somewhere that the standard allows initialization to happen later to "assist with dynamic loading of modules." I could see this being true when dynamic linking: I wouldn't expect a global initialized in a library to be initialized before I dlopen'ed the library. However, within a grouping of statically linked together translation units (my app's direct .o files) I would find this behavior very unintuitive. Does this only happen lazily when dynamically linking or can it happen at any time? (or was what I read just wrong? ;)

Pringle answered 6/8, 2009 at 14:26 Comment(0)
S
6

The standard has the following in 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.

But o Of course you can never officially tell when the initialization takes place since the initialization will occur before you access the variable! as follows:

// t1.cc
#include <iostream>
int i1 = 0;

int main () {
  std::cout << i1 << std::endl

// t2.cc
extern int i1;
int i2 = ++i1;

I can conform that g++ 4.2.4 at least appears to perform the initialization of 'i2' before main.

Sergias answered 6/8, 2009 at 14:56 Comment(7)
Actually, you can tell. Consider two translation units: A and B. An initializer in B increments a global in A (initialized to 0). main() simply prints the value of the global in A. Will it be 0 or 1?Dutiable
Is namespace scope distinct from global scope? If I take the globals out of any namespace is it defined in the standard rather than implementation defined?Pringle
@Joseph: no, the global scope is an outermost namespace scope. When the standard says "namespace scope", it means "not automatics or local statics", it doesn't mean "you wrote namespace blah {} around it".Sadoc
In addition, if the initialization occurs lazily then the compiler must generate code that checks to see if it is initialized and perform the initialization. This can wreak havoc when there are multiple threads - this code must be thread safe and c++ does not officially sanction threads - and when it is made thread safe, this thread safe check and possible initialization may be more computationally expensive than expected.Complex
namespace scope is basically anything not in function or class scope. Whether it is defined in the global namespace or in a user-defined namespace under it does not matter.Mete
Here is my pet-peeve about "global scope": #424323 . Anyway, I think you wanted to write 'i2', not 'b' in the last sentence :)Pancake
I recently sent an issue report about that paragraph, too: groups.google.com/group/comp.std.c++/browse_thread/thread/…Pancake
C
1

The problem that one wanted to solve with that rule is the one of dynamic loading. The allowance isn't restricted to dynamic loading and formally could happen for other cases. I don't know an implementation which use it for anything else than dynamic loading.

Chari answered 6/8, 2009 at 14:59 Comment(0)
I
0

Let's review a pseudocode:

In DLL:

static int ItsDllVar = 1;
int EXPORTED_FUNCTION() { return ItsDllVar; }

In application:

static int AppVar1 = 2;
static int AppVar2 = EXPORTED_FUNCTION() + AppVar1;

So according to static initializing AppVar2 gets 1+2=3

Lazy initialization applicable for local static variables (regardless of DLL)

int f()
{
    static int local_i = 5;//it get's 5 only after visiting f()
    return local_i;
}
Inexpedient answered 6/8, 2009 at 14:48 Comment(0)
B
0

I think this is what happened in my case with g++ 4.7 and CMake (not sure if this is a relevant detail regarding CMake). I have a code that registers a function in the factory. It relies on the constructor calling from a globally initialized variable.

When this code was in the statically linked library the initialization didn't happen! It is now working fine, when I moved it to the object files that linked directly (i.e., they are not combined into a library first).

So, I suspect that you are correct.

Bookkeeping answered 16/9, 2013 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.