• entries
    109
  • comments
    175
  • views
    116757

Notes about singletons in C++

Sign in to follow this  
Emmanuel Deloget

223 views

Wot! Did I stop to work on my text RPG? Que nenni. This is an article I prepared last year, when I was young and self confident about my own knowledge. Anyway I thought you could find this interesting (and don't forget to discuss about this in the comments. I tend to believe that I don't get anough comments - I'm pretty sure that it is because you find me boring and dull and stupid and... yes, I'm kidding).

Before reading anything else, you have to read another journal - [Washu]'s one. Last year, he wrote a 3 part entry about singletonisis, a (helas) common programmer illness. For information, references as added to my Small reference collection at the top of my journal.

As it seems very simple, the singleton pattern is a very popular pattern. Unfortunately, it is not simple, and the consequence of this is that most users don't use it correctly. The goal of this journal entry is to spot a number of common mistakes in singleton implementations and to correct them while explaining the pro and the cons of the pattern itself.

But since I target a midbie audience (those who have a decent knowledge of C++ but don't consider themselves as gurus), I believe I have to say something about the pattern itself: what exactly is a singleton?

The definition


To quote the [GoF], the intent of the singleton pattern is to "Ensure a class only has one instance, and provide a global point of access to it".

The first point is "ensure a class only has one instance", and the key word in this point is not "single" but "ensure". The first goal of a singleton is not to declare an instance of a class - a global variable would act the same - but to ensure that you won't be able to create more than one instance. This is quite different.

The second point is probably even more important: "provide a global point of access to it". Again, the key word is not "global" here, but "point of access". What does this mean? Simply that any access to the singleton is controlled, which in turn means that I can do whatever I want to protect the accesses to my singleton object. This is rather important, probably more important than the first point.

Are you sure you carefully read the definition above? If you still think that a singleton is no more than a convoluted global variable, please, return to the previous paragraph and reread it until you fully understand it. This is really important, because the rest is only an implementation problem.

Studying common implementations


I did a fast survey on how you, gdnet users, implemented your singleton. There are some good ones, some less good ones, and some bad ones. First, let's see the bad ones.

Construction and destruction, the basics


The following (slightly modified) code has been borrowed from an gdnet thread
template  ISingleton : public BaseClass
{
static BaseClass *mInstance;
public:
ISingleton() { ... }
virtual ~ISingleton() { ... }

static BaseClass* instance() { ... }
};


There are at least 2 major errors in this design, so let's spot them.

First, nothing forbids me to do :
    MyBaseClass myVariable;

And one of the singleton intent is completely defeated by this single line. I get the same result if I write
    ISingleton myVariable;

What is the problem here? The answer is simple: public constructor. When I have a public constructor in class A, nothing can forbid me to create any number of instances of A.

Next point: what will happen if I write
    delete ISingleton::instance();

The code compiles just fine, bu of course any subsequent use of the singleton will crash the program. Again, this is due to another public member: the destructor, this time.

Construction and destruction, a no-no


I only saw this code once on gdnet, and I can't remember where I found it. The only thing I remember is a great black hole and then nothing. I believed I was in Hell.
Let's see the Horror in action (I heavily modified the code so that the OP will not be able to recognize it - I don't want him to kill me).
class Singleton
{
static Singleton * mInstance;
public:
Singleton() { mInstance = new Singleton(); }
~Singleton() { delete mInstance; }
static Singleton *instance() { return mInstance; }
};

Do you understand me? Here, I have the same problem as before, and even worse, because I modify the singleton when I instantiate it. But the worse is probably the recursive call in the constructor.
How do this singleton works? It doesn't work at all, and I suspect the OP to have written this on the board without testing. Let's examine how it should work then.
When I call Singleton::instance(), I get the static member mInstance, which is not initialised yet, because no instance of Singleton has been created. So let's create one:
    Singleton singleton;

Yeah. Now, the instance is created and it creates the mInstance. And this instance creation is cool, because it creates a third instance. And then a fourth, and so on. Double yeah, this code is recursive and never-ending.
Let's correct the problem by adding guards then:
class Singleton
{
static Singleton * mInstance;
public:
Singleton() { if (!mInstance) mInstance = new Singleton(); }
~Singleton() { delete mInstance; }
static Singleton *instance() { return mInstance; }
}

Ok, we get rid of the recursivity. We still have a problem: to create the singleton instance, we need to instantiate the singleton. Sounds quite illogical since we want to have only once instance at at time. It is even worse: the destructor deletes my instance, so if I want this instance to last until the program death, I have to set up a global variable. You said it: OMG!

What is the problem here? Again, it is a constructor/destructor problem. None of them should play a role in the static instance creation, because it leads to at least one level of recursivity, meaning that I'll need to create an instance of a singleton to init my singleton's instance - and I'll have two singletons then.

Singleton, the Ogre 3D approach


One thing that bugs me with this otherwise wonderfull 3d engine is the singleton management. To create the Ogre::Root object, you must instantiate it using the new operator. Once you've done this, you are able to use it as a singleton.

// init
m_pOgreRoot = new Ogre::Root(szPlugins, szConfig, szLog);
// this call will crash if the Root object hasn't been created yet
Ogre::Root::getSingleton().doSomething();
// at the end of the software wa are allowed to delete the ogre singleton!
delete m_pOgreRoot;

IMHO, a better approch would have been to do an initialization function
// init
Ogre::Root::getSingleton().init(... param list...);
// this call won't crash, but doSomething() can throw an exception if
// something should have been initialized before
Ogre::Root::getSingleton().doSomething();
// to explicitely destroy the singleton, I need another method
// -- this is rather bad, since it may be called at any time and might
// -- do rather bad things in the end
Ogre::Root::destroySingleton();

This allow the singleton to be always valid - which is, I think, far better and less error prone.

A better approach


Let's write the code
class Singleton
{
static Singleton *mInstance;
Singleton() { }
~Singleton() { }
public:
static Singleton *instance() { ... }
};

What is the problem of such code? It seems good enough.
Well, not exactly. I can still play with it:
    Singleton mySingleton(*Singleton::instance());

What did I do here? I created a copy of my singleton. What will the compiler say? Nothing. If you don't provide a copy constructor, it will provide a default one for you. Quite cool, isn't it?
Again, I have two instances of my singleton, which is obviously not a good thing.

The beginning of a solution


The last piece of code was rather good, expect for the copy constructor problem, but this problem is easily solved by adding a non-default private copy constructor:
class Singleton
{
static Singleton *mInstance;
Singleton() { }
Singleton(const Singleton& s) { }
Singleton& operator=(const Singleton& s) { return *this; }
~Singleton() { }
public:
static Singleton *instance()
{
if (!mInstance)
{
mInstance = new Singleton();
}
return mInstance;
}
};

Let's try to summarize the strength of this implementation:

  1. we cannot create an instance of the singleton using the default constructor, because it is private.
  2. we cannot create a copy of a singleton instance
  3. we cannot destroy the singleton out of he singleton class because its destructor is also private
  4. since we defined the copy constructor, we also define the operator=() - this is commonly refered as a good practice

The first two points make it clear than I cannot create more than one instance of my singleton object - thus the 'single instance' intent is really enforced. The third point avoids me to accidentally destroy my singleton instance - which is rather cool.

There is still at least one problem in this simple implementation: I have no way to control the lifetime of my singleton, mostly because I don't know when I should destroy it (moreover, I forbid myself to destroy it from the outside of the class, so I just can't delete it when I decide I'll no longer use it).

On singleton lifetime, the first approach


A common mistake I often saw of these boards is to use the following:
class Singleton
{
static Singleton mInstance;
Singleton() { }
Singleton(const Singleton& s) { }
~Singleton() { }
public:
static Singleton *instance()
{
return &mInstance;
}
};

It seems to resolve the life time problem - the singleton will de destroyed at the end of the program.
Actually, this solution is worse than the previous code, because you can't know if the singleton is created if you try to use it before main() is called (for example, in the constructor of another singleton). Singleton::instance() can return a pointer to invalid memory, and your program will crash.

On singleton lifetime, Meyers' approach


Another solution is to use what is called Meyers singleton - first expressed in [SM-2] IIRC (the third edition of [SM-1] also uses it).
class Singleton
{
Singleton() { }
Singleton(const Singleton& s) { }
~Singleton() { }
public:
static Singleton *instance()
{
static Singleton theInstance;
return &theInstance;
}
};

This code ensure that the singleton will be created when it is needed (because the C++ standard tell us that a static variable in a function is created the first time you enter in the function. Since it is a static instance, and not an allocated one, it will be destroyed at the end of the program. It seems good now - we have our final candidate!

Well, not exactly. There is still an embarrassing problem here, because of the order of destruction of static instances. The standard says they are destroyed in the inverse order of their creation - it means that if a static instance of A uses my singleton in its constructor, then my singleton will be destroyed before my instance of A. What if A destructor tries to use the singleton? Again, I'll crash my program.

The real solution is...


...nothing. There is no real solution to this problem. Meyers singleton is quite good, but has still some drawbacks. It can be extended - because it is rather easy to know if the instance of your singleton is still valid or not (monitor your singleton destructor) but once you detect it, it becomes tricky. If the singleton holds some important resources, they are probably destroyed too, and maybe you don't have any way to recreate them. If it is not the case, you can try to recreate the singleton - it is possible, using placement new.

Templated singletons


A templated singleton has to obey to every rule I described in the comments above, and these rules also apply to the client class (the template parameter). Moreover, the client class have to declare the singleton template class as friend because there is no other way to gain access to the constructor of the client class. Some of you might object that it is possible to set the constructors and destructors as protected (and since our singleton template class inherit the base class, it automatically gains access to the methods he needs). While this is a possible solution, it is not technically viable: what does forbid me to inherit a dumb class from the base class in order to bypass the singleton limitations?

There is at least one more problem with templated singleton:

  • the client class construction is limited to a very simple construction - either the default one or a particular one that have to be the same or each declared singleton.
  • to avoid this problem, you have to declare a construction policy - but then is creates another problem: there is no other way to declare the creation policy but to declare it as a template parameter, because feeding the instance() method with a function pointer is not an acceptable solution. Since it is a template parameter, it means that the singleton type you declare is dependant upon this policy, i.e. if you change the policy, you change the singleton type. Unfortunately, static members are common to every instances of a particular class. In our case, it means that we can create two singleton ot type MyType by changing the creation policy. This is weird.

[AA-1] gives an in-depth explaination of a templated singleton class that can be extended using policies - I suggest you to read it if you plan to implement this.

Using the singleton pattern


As you already know, this pattern should not be used instead of a global variable - mostly because you should not have any global variable. Again, the [GoF] tells us what is the applicability of the singleton pattern:
Quote:

Use the Singleton pattern when
  • there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point.
  • when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code.

I think I have to put the emphasis on the second part of the first point: and it must be accessible to clients from a well-known access point. Using the singleton pattern just because you believe that only one instance of a particular object is needed is called lazyness (the first symptom of singletonisis). But if you need to control the access of this object then yes (for example, only calls from a particular thread can succeed), you just found a good singleton candidate.
You found it by yourself, singleton are rare, very rare. Fortunately, it is still possible to find good examples: a multi-threaded pool-based memory manager might be one of them (the fact that you are working in a multi-threaded environment force you to protect the memory manager access). [AA-1] cites some other possible uses of the singleton pattern, but some of these are questionable IMHO.

Avoiding the singleton pattern


As you might see from this entry, it is rather hard to implement a correct singleton. It is even harder to know when to use it. As a consequence, it should be nice to avoid it whenever possible. Of course, the singleton offers nice opportunities, and its rather cool to announce in a meeting "let's use the singleton pattern" (I did it several time just to see my coworkers' faces). But let's face it: it is difficult to use. How to avoid using it then? [Washu] gives a very good answer to this question: refactor!

Conclusion


There are still numerous issues with the singleton pattern that hasn't been addressed here. For example, is you singleton thread safe or do you need to protect its use? This question and similar ones are not the purpose of this journal entry. Moreover, there are some more complete resources about singletons - the best one I ever read is in [AA-1] - I suggest you to read it if you want to learn more about singleton and a lot of other subjects. In particular, [AA-1] address the problem of Meyer's singleton destruction in an elegant way, using the so-called phoenix singleton. It also deals with a lot of other implementation issues.

I tried to give you some solution to create a correct singleton. But correct is by no mean a synonym for perfect, and you can sill abuse the C++ syntax to do bad things with singleton.

Thou are warned :)
Sign in to follow this  


4 Comments


Recommended Comments

Eeeeewwwww Singletons!

When I require some deconstructor code where a single interface is needed, I usually implement a static "Lifetime" object which calls the interface's deconstructor code when it's destroyed. It's quite a nice solution when it comes to C#....

Share this comment


Link to comment
But then you have to be sure that you static Lifetime object destructor will be called after any other static instance had been destroyed. This is not possible in C++, unless you find a way to order your static object creation.

Its seems that this journal entry is a bit long... I may have splitted (correct tense?) it in two or more parts.

Share this comment


Link to comment
My name is Nit, and I have singletonitis. I'm on singleton overload after reading both your post and Washu's posts. Furthermore, i've been reading through my design patterns book from start to finish. Coincidentally, I just reached the Singleton Pattern chapter last night. I was going to skip that chapter, but I feel that I should read it thoroughly so that I can absorb these "do's and don'ts".

Thanks for the article.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now