In C ++, does a "static initialization fiasco" only occur when accessing a data member of an object defined in another module?
Is the following example legal and safe C ++, or will it blow up depending on which customer decides to call the constructors of the global objects?
a.hpp:
class A {
public:
A(int val_);
int val;
};
extern A a;
a.cpp:
#include "a.hpp"
A::A(int val_) : val(val_) {}
A a(1234);
b.cpp:
#include <cassert>
#include "a.hpp"
class B {
public:
B(A &a);
int &ref;
};
B::B(A &a) : ref(a.val) {}
B b(a);
int main(int argc, char **argv) {
assert(b.ref == 1234);
assert(&b.ref == &a.val);
}
I need to do something like this in some real code I am writing (obviously my classes A and B are much more complex than this minimal example, but the data members they have to share are plain old int and bools) and I would rather use links than pointers.
source to share
Yes, this can blow up (according to the standard, anyway) because the constructor b
can work before a
and then ([class.cdtor] / p1) ...
For an object with a non-trivial constructor, referencing any non-static member or base class of the object before the constructor starts executing results in undefined.
source to share
Your question is correct, but I think the module it is built a
in will be statically initialized correctly before the instance b
can access it, and this should be especially true if you build a
in another shared object and the class b
has an explicit, non-circular dependency from the class a
as in your example. This can also be easily tested on compilers / deployment platforms.
If you're still not convinced, you should force-initialize a
before b
with a free function a()
, as described here (Build on first use of the idiom):
Title:
A& a();
Compilation block:
A& a()
{
static A _a;
return _a;
}
Then you link _a
to a()
.
source to share