About two kinds of singleton pattern in C++
When I look for informations about the singleton pattern for C++, I always find examples like this:
class Singleton
{
public:
~Singleton() {
}
static Singleton* getInstance()
{
if(instance == NULL) {
instance = new Singleton();
}
return instance;
}
protected开发者_JS百科:
Singleton() {
}
private:
static Singleton* instance;
};
Singleton* Singleton::instance = NULL;
But this kind of singleton also seems to work as well:
class Singleton
{
public:
~Singleton() {
}
static Singleton* getInstance()
{
return &instance;
}
protected:
Singleton() {
}
private:
static Singleton instance;
};
Singleton Singleton::instance;
I guess that the second singleton is instantiated at the beginning of the program, unlike the first, but is it the only difference?
Why do we find mainly the first?
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
The static initialization order fiasco is a very subtle and commonly misunderstood aspect of C++. Unfortunately it's very hard to detect — the errors often occur before main() begins.
In short, suppose you have two static objects x and y which exist in separate source files, say x.cpp and y.cpp. Suppose further that the initialization for the y object (typically the y object's constructor) calls some method on the x object.
That's it. It's that simple.
The tragedy is that you have a 50%-50% chance of dying. If the compilation unit for x.cpp happens to get initialized first, all is well. But if the compilation unit for y.cpp get initialized first, then y's initialization will get run before x's initialization, and you're toast. E.g., y's constructor could call a method on the x object, yet the x object hasn't yet been constructed.
The first method you listed avoids this problem completely. It's called the "construct on first use idiom"
The downside of this approach is that the 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.
The first one allows you to delete the instance while the second one does not. But please be aware that your first example is not thread safe
It's commonly known as the static
initialization order fiasco. In summary, static instances at file scope are not necessarily initialized before explicit function calls that create one as in your first example.
The singleton patterns is commonly considered Bad Practice, so empirical evidence (what you "see most") is of little value in this case.
The first version uses dynamic allocation, while the second one uses static allocation. That is, the second allocation cannot fail, while the first one could possibly throw an exception.
There are pros and cons to both versions, but generally you should try for a different design that doesn't require singletons at all.
The first one is also "lazy" - it will be created only if and when it is needed. If your Singleton
is expensive, this is probably what you want.
If your Singleton
is cheap and you can deal with undefined order of static initialization (and you don't use it before main()), you might as well go for the second solution.
精彩评论