Is it possible to initialize the Instance of a Singleton when it is really needed?
Consider this pattern taken from the famous "Design Patterns":
class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
}
Singleton* Singleton::_instance = 0; // unit.cpp
static Singleton* Singleton::Instance() {
if (_instance == 0) {
_instance = new Singleton;
}
return _instance;
}
Now, I think there is a problem in the pattern there, if one desires to provide the Singleton in a library to others: if the user calls Singleton::Instance()
from another compilation unit (during a static data member initialization, for example) before _instance is initialized, then a following call of Singleton::Instance()
might create another instance of the Singleton, with unwanted results, since _instance might have been initialized to 0 first.
I think one solution is to initialize _instance this way:
Singleton* Singleton::_instance = Singleton::Instance();
Anyway, that makes the initialization not "lazy" for those who don't need to call Singleton::Instance() to initialize their static data.
Are there better solutions so that the inizialization can happen when the Singleton instance is needed?
The singleton solution you have quoted works because
Singleton* Singleton::_instance = 0;
describes a static initialization (namely zero initialization in this case, but a constant initialization would work as well if used), which is guaranteed to happen before any dynamic initialization (and therefore before any code is run). All requirements of static initialization are guaranteed here, as _instance is a global variable of a built-in type (a pointer) and initialized with zero.
The other solution you have provided does not change anything significant, because still only the zero initialization of _instance is guaranteed to happen before code from other modules is called, as the initialization by Singleton::Instance call is a dynamic one and therefore is subject to static initialization order fiasco.
Note: Static initialization is most often implemented by storing the value of the variable, which was computed compile time, in a data segment of the executable.
While most programmers (including Bjarne Stroustrup) call the initialization style used in the original singleton implemementation "compile time initialization", the standard calls it "static initialization", as opposed to a "dynamic initialization" (which is what is most often called run-time). See C++0x draft 3.6.2 (shortened, emphasis mine):
3.6.2 Initialization of non-local variables [basic.start.init]
... Non-local variables with static storage duration are initialized as a consequence of program initiation. ... as follows.
2 Variables with static storage duration (3.7.1) ... shall be zero-initialized (8.5) before any other initialization takes place.
Constant initialization is performed: ...
- if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With