Singling out Singleton

Out of all the design patterns that I’ve used in my professional career, Singleton is the one I’ve used the least. Don’t get me wrong. In my experience, as developers we are fascinated with the ability to refer to a single instance, and in our quest to master the pattern we whip up naive implementations that bring more problems than solutions. Most of time one can solve the single instance problem by creating, well, a single instance (in UML terms, a Singleton has both cardinality and multiplicity of 1).  If you and your team have control of the code, why would you want to create a Singleton when you can easily make sure only one instance of a given class is created?   The main reason I don’t use Singleton is because it is misunderstood: Singleton isn’t about a single instance, it is about a single state.  That’s right.  Singleton makes sure that the object state is consistent–meets its invariants–by providing a single point of entry. However, there is another design pattern called MonoState that addresses the problem more elegantly and does not have many of the issues from Singleton. It was originally published in C++ Report, now a defunct magazine.  You can find a nice explanation of it here.

If you’re still intent to whip up your own Singleton, there are two problems to solve: lifetime and thread-safety.

Regarding lifetime, if your Singleton lifetime is independent, a simple implementation that I used in the past makes used of the Nifty Counter technique, described in the C++ ARM [1] and  by John Lakos [2]. It uses C++ ’98 but can easily be converted to C++ ’11, and it does not provide Double-Checked Locking, albeit experts will argue that DCL is broken. In addition, there have been several approaches discussed, particularly in Alexandrescu [3] and Vlissides [4], and one can find Singleton implementations in Boost. One of the differences with the approach explored by Andrei ultimately makes use of atexit(), while a Singleton using the nifty counter technique will be deallocated after all the calls to atexit() have completed. That may not seem like much, but if you’re looking for extra flexibility, this might be what you need.

Listing 1 (singleton.h):

class NiftySingletonDestroyer;

class Singleton {
 static Singleton* _instance;

 Singleton(const Singleton&);
 Singleton& operator=(const Singleton&);

 friend class NiftySingletonDestroyer;
 Singleton();
 ~Singleton();
public:
 static Singleton* Instance();
};

static class NiftySingletonDestroyer {
 static int counter;
 public:
  NiftySingletonDestroyer();
  ~NiftySingletonDestroyer();
 } aNiftySingletonDestroyer;

Listing 2 (singleton.cpp):

#include "singleton.h"
Singleton* Singleton::_instance = 0;
Singleton::Singleton() {}
Singleton::~Singleton() {}

Singleton* Singleton::Instance() {
  if (!_instance) {
    _instance = new Singleton();
  }   
  return _instance; 
}

int NiftySingletonDestroyer::counter;

NiftySingletonDestroyer::NiftySingletonDestroyer() { ++counter; }
NiftySingletonDestroyer::~NiftySingletonDestroyer() {
  if ( --counter == 0 && Singleton::_instance ) 
    delete Singleton::_instance;
}

Note the declaration of the NiftySingletonDestroyer:

static class NiftySingletonDestroyer {}...

as being a static class.  This basically does the trick.  Every time you do a #include "singleton.h" there will be a NiftySingletonDestroyer constructed, incrementing the counter for that compilation unit when it is loaded at runtime.  When the program is unloaded, there will be a call to the destructor, therefore decrementing the counter and eventually destroying the Singleton.

References

1. Ellis, Margaret, A. and Bjarne Stroustrup, The Annotated C++
Reference Manual, Section 3.4, pp. 20-21, Addison Wesley, Reading, MA,
1990
2. Lakos, John, Large-Scale C++ Software Design, Chapter 7, pp.
537-543
Addison Wesley, Reading, MA 1996.
3. Alexandrescu, Andrei, Modern C++ Design, Addison-Wesley, Reading,
MA 2001.
4. Vlissides, J. Pattern Hatching: Design Patterns Applied,
Addison-Wesley, Reading, MA 1998.

This entry was posted in design patterns and tagged . Bookmark the permalink.

2 Responses to Singling out Singleton

  1. Pingback: CPPCON2020 Session Review: Retiring the Singleton Pattern: Concrete suggestions for what to use instead | Se Habla C++

  2. Pingback: If you build it, will they come? | Se Habla C++

Leave a comment