views:

5042

answers:

5

C++ guarantees that variables in compilation unit (.cpp file) are initialised in order of declaration. For number of compilation units this rule works for each one separately (I mean static variables outside of classes) , but order between them is undefined.

Where I can see some explanations about this order for gcc and MSVC (I know that relying on that is a very bad idea - it is just to understand the problems that we may have with legacy code when moving to new GCC major and different OS) ?

Thanks

+8  A: 

As you say the order is undefined across different compilation units.

Within the same compilation unit the order is well defined: The same order as definition.

This is because this is not resolved at the language level but at the linker level. So you really need to check out the linker documentation. Though I really doubt this will help in any useful way.

For gcc: Check out ld

I have found that even changing the order of objects files being linked can change the initialization order. So it is not just your linker that you need to worry about, but how the linker is invoked by your build system. Even try to solve the problem is practically a non starter.

This is generally only a problem when initializing global that reference each other during their own initialization (so only affects objects with constructors).

There are techniques to get around the problem.

  • Lazy initialization.
  • Schwarz Counter
  • Put all complex global variables inside the same compilation unit.
Martin York
My own preference goes for all globals in the same compilation unit... :-)
paercebal
Preferably one would not need globals at all.
Martin York
You both right but unfortunately this was unknown to generations of programmers who wrote tons of libraries and 3rd party code we got to use...
Dmitry Khalatov
+1  A: 

I expect the constructor order between modules is mainly a function of what order you pass the objects to the linker.

However, GCC does let you explicitly specify the ordering for global ctors:

class Thingy
{
public:
    Thingy(char*p) {printf(p);}
};

Thingy a("A");
Thingy b("B");
Thingy c("C");

outputs 'ABC' as you'd expect, but

Thingy a __attribute__((init_priority(300))) ("A");
Thingy b __attribute__((init_priority(200))) ("B");
Thingy c __attribute__((init_priority(400))) ("C");

outputs 'BAC'.

A: 

In addition to Martin's comments, coming from a C background, I always think of static variables as part of the program executable, incorporated and allocated space in the data segment. Thus static variables can be thought of as being initialised as the program loads, prior to any code being executed. The exact order in which this happens can be ascertained by looking at the data segment of map file output by the linker, but for most intents and purposes the initialisation is simultaeneous.

Edit: Depending on construction order of static objects is liable to be non-portable and should probably be avoided.

Shane MacLaughlin
The problem occurs when you have C++ classes whos constructors have side-effects (say, they reference each other).
Personally, i try to avoid this where ever possible, as my experience of this (os possibly lack of knowledge) has not been good. Usually I either move the bulk of the construction to an Init function, called at startup, or change from static to a global pointer initialised on the heap at startup.
Shane MacLaughlin
@smacl : Of course, but then you must handle and Finalize function to deallocate the data, and handle the fact that sometimes both Init and Finalize are called multiple times, and sometimes, concurrently. The RAII idiom, here, combined by automatic initialization of globals in a DLL is quite welcome
paercebal
A: 

Hi, ThankX for the answers.

The sugested "attribute((init_priority(300)))" method works well for gcc. Is there a similar method for Microsoft VC++ compiller?

Shanaka Dharmawardhana