|
||||
Section 10:
|
[10.15] How do I prevent the "static initialization order fiasco"?
Use the "construct on first use" idiom, which simply means to wrap your static object inside a function. For example, suppose you have two classes, Fred and Barney. There is a global Fred object called x, and a global Barney object called y. Barney's constructor invokes the goBowling() method on the x object. The file x.cpp defines the x object: // File x.cpp #include "Fred.h" Fred x;The file y.cpp defines the y object: // File y.cpp #include "Barney.h" Barney y;For completeness the Barney constructor might look something like this: // File Barney.cpp #include "Barney.h" Barney::Barney() { ... x.goBowling(); ... }As described above, the disaster occurs if y is constructed before x, which happens 50% of the time since they're in different source files. There are many solutions to this problem, but a very simple and completely portable solution is to replace the global Fred object, x, with a global function, x(), that returns the Fred object by reference. // File x.cpp #include "Fred.h" Fred& x() { static Fred* ans = new Fred(); return *ans; }Since static local objects are constructed the first time control flows over their declaration (only), the above new Fred() statement will only happen once: the first time x() is called. Every subsequent call will return the same Fred object (the one pointed to by ans). Then all you do is change your usages of x to x(): // File Barney.cpp #include "Barney.h" Barney::Barney() { ... x().goBowling(); ... }This is called the Construct On First Use Idiom because it does just that: the global Fred object is constructed on its first use. The downside of this approach is that the Fred object is never destructed. There is another technique that answers this concern, but it needs to be used with care since it creates the possibility of another (equally nasty) problem. Note: The static initialization order fiasco can also, in some cases, apply to built-in/intrinsic types. |