This is another variation of an old theme: The initialization order of static objects in different translation units is not defined.
Below is a stripped-down example of my particular scenario. The classes G and F are non-POD types. F depends on G is the sense that to construct an instance of F you need some number of instances of G. (For example, F could be some message an application emits, and instances of G would be components of such messages.)
G.hpp
#ifndef G_HPP
#define G_HPP
struct G
{
G() {} // ...
};
inline G operator+(G, G) { return G(); }
#endif
Gs.hpp
#ifndef GS_HPP
#define GS_HPP
#include "G.hpp"
extern const G g1;
extern const G g2;
extern const G g3;
extern const G g4;
extern const G g5;
extern const G g6;
extern const G g7;
extern const G g8;
extern const G g9;
#endif
Gs.cpp
#include "Gs.hpp"
const G g1;
const G g2;
const G g3;
const G g4;
const G g5;
const G g6;
const G g7;
const G g8;
const G g9;
F.hpp
#ifndef F_HPP
#define F_HPP
#include "G.hpp"
struct F
{
F(G) {} // ...
};
#endif
Fs.hpp
#ifndef FS_HPP
#define FS_HPP
#include "F.hpp"开发者_C百科
extern const F f1;
extern const F f2;
extern const F f3;
#endif
Fs.cpp
#include "Fs.hpp"
#include "Gs.hpp"
const F f1(g1 + g2 + g3);
const F f2(g4 + g5 + g6);
const F f3(g7 + g8 + g9);
F's constructor takes an argument which is the result of applying
operator+
to instances of G. Since the instances of both F and G are
global variables, there is not guarantee that the instances of G have
been initialized when the constructor of F needs them.
The particularity here is that there are many Gs and Fs all over the place, and I would like to keep the syntax as much as possibly close to the code posted above, while still enforcing the construction of a G whenever an F needs it.
From http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.15 .
Change your global objects into functions which construct the object on first use.
// Gs.hpp
const G & g1();
// Gs.cpp
const G & g1() {
static const G* g1_ptr = new G();
return *g1_ptr;
}
// Fs.cpp
const F & f1() {
static const F* f1_ptr = new F(g1() + g2() + g3());
return *f1_ptr;
}
Or if you really can't stand adding the extra ()
s, use some #define
s to hide them:
// Gs.hpp
const G & get_g1();
#define g1 (get_g1())
// Definition of get_g1() like g1() from prev. example
Keep the extern declarations in the headers. Put all the fN
and gN
definitions into a single cpp file in the appropriate order.
Maybe a trick similar to the one used to initialize cin
and friends' filebuffers would work for you? (Read <iostream>
carefully.)
精彩评论