Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static initialization in one compilation unit

Static initialization is well described subject, here and even at this site here

And everywhere it is written that problem will occurs if there exists different compilation units with related static variables. And if static variables exists in one compilation unit, there shouldn't be problem: they will be initialized in order of their position in file.

But I have this code:

template <typename T>
class A{
public:
    int _data;
    T _obj;
    A(int data) :_data(data){}
};

template <typename T>
class B{
public:
    const static B<T> nullObj;
    B(int data) :_a(new A<T>(data)){}
    A<T> *_a;
};

template <typename T>
class C{
public:
    const static C<T> nullObj;
    C() :_a(nullObj._a){}
    C(bool t) :_a(B<T>::nullObj._a){
        _a->_data++; //FAILS HERE!
    }
    A<T> *_a;
};

template <typename T>
const B<T> B<T>::nullObj(0);

template <typename T>
const C<T> C<T>::nullObj(false);

class _B{};
class  _A{ public: _A(){}; C<_B> g; };

int main(){
    return 0;
}

And it fails at runtime before entering main() function, because it tries to initialize const C<T> C<T>::nullObj(false); before const B<T> B<T>::nullObj(0); is initialized. Despite their position in one file.

Why does it tries to initialize second static variable before first static variable? Does there exist chapter in C++ Standart where described real situation with sequence of static initialization?

like image 410
Arkady Avatar asked Aug 27 '14 11:08

Arkady


1 Answers

C++ Standard, section 14.7.1 [temp.inst]:

Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist


C<T> is instanciated before B<T>, so the order of initialization is well defined, and is :

1) const static C<T> nullObj;

2) const static B<T> nullObj;

Since C constructor dereference B<T>::nullObj._a, you have undefined behavior.

Solution:

You must use the static member B<_B>::nullObj somehow for it to be initialized, e.g. if you do :

class _B{};
class _A{ public: _A() : b(B<_B>::nullObj) {}; B<_B> b; C<_B> g; };

Then B<_B>::nullObj is indeed initialized before C constructor needs it

like image 99
quantdev Avatar answered Sep 22 '22 19:09

quantdev