0

I was wondering why sometimes my global const defined in seperate .h file isn't properly initialized when I need it. Some tests lead me to situation that I can't understand. I don't know how to explain it, so here's the code:

main.cpp

#include <iostream>
#include "class.h"
using namespace std;

A a;
B b;

int main(int argc, char* argv[]){
A aa;
B bb;
cout<<a.a<<" "<<aa.a<<endl;
cout<<b.b<<" "<<bb.b<<endl;
return 0;
}

class.h

#ifndef CLASS_H
#define CLASS_H
#include "const.h"

class A {
public:
A();
float a;
};

class B {
public:
B():b(CONST){}
float b;
};
#endif

class.cpp

#include "class.h"
A::A()
: a(CONST){}

const.h

#ifndef CONST_H
#define CONST_H
#include <limits>
using namespace std;

const float CONST = numeric_limits<float>::has_infinity ? 
        -numeric_limits<float>::infinity() : 
        -numeric_limits<float>::max();
#endif

After running above code I get:

0 -1.#INF
-1.#INF -1.#INF

when actually I would like to get 4 times '-1.#INF'. Why does it happen this way? If CONST would be '1' instead of above formula, it would work perfectly.

I can "fix" it by making static getConst() method:

static float getConst(){
static const float CONST = numeric_limits<float>::has_infinity ? 
        -numeric_limits<float>::infinity() : 
        -numeric_limits<float>::max();
return CONST;}

but it just doesn't "feel" right. On other hand I just need two of those above... But maybe there's some other way?

And, most importantly, why class B gets "right" CONST and class A don't?

Koger
  • 1,783
  • 2
  • 23
  • 34

4 Answers4

3

The order of initialization of global object in different translation unit is not guarantee.

Please have a look at this stackoverflow question: Static variables initialisation order

Community
  • 1
  • 1
Alessandro Teruzzi
  • 3,918
  • 1
  • 27
  • 41
  • Thanks, that explained a lot. Funny thing is, I believe that it should behave the same way all the time now, as I'm using the same compiler etc., but as I opened and recompiled this project seconds ago, it initializes CONST soon enough for A::a to initialize properly – Koger Dec 09 '10 at 12:36
2

Constant objects have internal linkage, so you get a separate copy of CONST in each compilation unit that includes const.h. In this case, you'll get one in main.cpp, and one in class.cpp. You also have your two global objects in main.cpp.

C++ does not define the order in which global objects in different compilation units are initialised. As constructor is called from main.cpp, and needs the global constant from class.cpp, which may not yet be initialised. In your particular case, it hasn't been, so you get the incorrect value you saw. Bs constructor is inline, so it uses the global constant from main.cpp, which has been initialised since it is defined earlier in the same compilation unit.

By making the constant a function-static object, it is now guaranteed to be initialised when that function is first called.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Wow, thanks for comprehensive answer. I hoped that the fact, that B was initialized properly and A not, was somehow caused by B's inline constructor, but it's just because main.cpp "got lucky", and class.cpp not. However, as I understand, there's no way that this const wouldn't be initialized before main fucntion starts running? – Koger Dec 09 '10 at 12:41
  • @Koger: B's correct behaviour is in fact guaranteed; within a single compilation unit, global objects are initialised in the order they are defined, and `CONST` is defined (in the header file) before `B`. And yes, they will all be initialised before `main` starts. – Mike Seymour Dec 09 '10 at 12:52
  • Isn't class.cpp single compilation unit as well? And it theoretically includes class.h and const.h the same way main.cpp does, so CONST is defined before A. – Koger Dec 09 '10 at 15:20
0

I don't see the contents of const.h anywhere so I can only guess what CONST is (a macro?).

That aside, in your code example, the member variable A::a is not initialized. Hence, it could have any value - it's uninitialized.

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
  • Looks like somebody edited my question to make it look more neat. Now const.h is more visible. And A::a is initialized in class.cpp file – Koger Dec 09 '10 at 12:26
0

If I'm understanding your question properly then I believe the problem is because the order of initialisation of any global objects is not defined.