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?
Constant objects have internal linkage, so you get a separate copy of
CONSTin each compilation unit that includesconst.h. In this case, you’ll get one inmain.cpp, and one inclass.cpp. You also have your two global objects inmain.cpp.C++ does not define the order in which global objects in different compilation units are initialised.
As constructor is called frommain.cpp, and needs the global constant fromclass.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 frommain.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.