C++11 generic singleton pattern

c11 generic singleton pattern - theimpossiblecode.com

You can argue against singletons, but IMHO some frameworks and designs simply can’t avoid them.  In this post we’re going to encapsulate it into a reusable template code using C++11. Moreover, we’re not going to compromise on simplicity, thread safety, performance and flexibility.

A REVISED DESIGN AND IMPLEMENTATION

Using C++11

The solution described here is using lambda expressions and the C++11 thread safety guarantee for function-local statics.

Why write a C++11 generic singleton pattern?

Why at all?

Design patterns are proven solutions to daily coding/design tasks. Hence, a generic pattern, based on templates, will make it easier for you to take this proven solution and easily apply it to your types without rewriting the code. Furthermore template based solutions are compile time type safe and help avoid runtime errors you might get from using the wrong types.

Why write your own?

You could use an external solution, like boost.serialization.singleton (a weak implementation IMHO), but sometimes this solution is either not fitting or you want to avoid an external dependency for something relatively small. Many times writing something small which fits exactly what you need can also be more efficient at runtime since it has your minimum tailored requirements.

Requirements

  • Most importantly, it must be simple to reuse the same implementation across all singletons use cases.
  • More than a single singleton can be constructed for the same type.
  • A singleton can be applied to any type which you can construct, not necessarily with a default constructor.
  • We want to defer the singleton initialization until the first use.
  • The singleton initialization is thread safe:
    • Only a single thread will initialize the singleton.
    • All the threads will use the same initialized instance.
  • Using  the singleton should be as fast as direct pointer access.

Implementation explained

Solving the requirements

  • For reusable code applied to any type in a non intrusive way, we’ll use a singleton template:
template <typename T>
class Singleton
{
public:
    // ...

private:
    static T *mpInstance;
};

template <typename T>
T *Singleton<T>::mpInstance;
  • Since we want more than a single singleton can be constructed for the same type, we need to have the static member be attached to something unique. We’ll get this with inheritance:
template <typename T, typename CONTEXT>
class Singleton
{
public:
    // ...
    
protected:
    Singleton()
    {
        // ...
    }

private:
    static T *mpInstance;
};

template <typename T, typename CONTEXT>
T *Singleton<T, CONTEXT>::mpInstance;

// Usage example:
struct StrSingleton : public Singleton<string, StrSingleton> {};
  • To enable any constructible T  type, we’ll use a default implementation which can be overridden. Since we’re using templates, we’ll do this the template way and not the polymorphic way. Here we count on the template mechanism to instantiate only what it needs and we’ll let the derived singleton decide which base constructor to call:
template <typename T, typename CONTEXT>
class Singleton
{
public:
    // ...

protected:
    Singleton()
    {
        // ...
        mpInstance = new T*;
    }

    Singleton(int)
    {
        // ...
        mpInstance = CONTEXT::init();
    }

private:
    static T *mpInstance;
};

template <typename T, typename CONTEXT>
T *Singleton<T, CONTEXT>::mpInstance;

// Usage example:
struct StrSingleton : public Singleton<string, StrSingleton>
{
    StrSingleton() : Singleton(1) {}
    static string *init() {return new string("Initialized");}
};
  • We defer the singleton initialization and make it thread safe by using a local static variable helper and the C++11 static variable initialization guarantee:
template <typename T, typename CONTEXT>
class Singleton
{
public:
    // ...

protected:
    Singleton()
    {
        static bool static_init = []()->bool {
            mpInstance = new T;
            return true;
        }();
    }

    Singleton(int)
    {
        static bool static_init = []()->bool {
            mpInstance = CONTEXT::init();
            return true;
        }();
    }

private:
    static T *mpInstance;
};
  • Using  the singleton is going to be as fast as direct pointer access by following these rules:
    • Constructing an instance of the Singleton and not invokink its getInstance() method on demand.
      • The getInstance() way of singletons invokes the double-check code all the time, which is not that bad, but comparing to optimizing without it costs at least 50% more on low end systems such as the Raspberry Pi.
      • There is a short discussion on this later on below.
    • Using the Singleton arrow/asterisk operators, which are inlined and optimized by the compiler.
template <typename T, typename CONTEXT>
class Singleton
{
public:
    // Very fast inlined operator accessors
    T* operator->() {return mpInstance;}
    const T* operator->() const {return mpInstance;}
    T& operator*() {return *mpInstance;}
    const T& operator*() const {return *mpInstance;}

protected:
    // ...

private:
    static T *mpInstance;
};
  • This is all the magic, and the implementation is short enough:

Examples of usage

Example 1 – general use case

  • First of all note there is no getInstance() or similar for minor performance reasons we’ll discuss below.
  • This is the most simple use case – see also the other examples below.

Example 2 – singleton initialization

  • Call the Singleton constructor with an int for it to invoke your static init() method.
  • You can do anything you need for initialization.

Example 3 – singleton variations using the same type

  • Singletons per type are unique in the same namespace automatically.
  • To add another Singleton for the same type in the same namespace you need to add a derived class from Singleton, use the same T, but pass your new derived singleton name as the CONTEXT template parameter.

A short discussion on speed

Here is a benchmarking test and a discussion for its results follows:

This test was built and executed on Raspberry Pi3 (the results on Intel i7 processor show test1/2/3 to work at about the same speed).

As you can plainly see using a getInstance() was much slower than the arrow/asterisk access operators.  The reason is that the compiler can’t optimize very well the inline code in getInstance(). If you look at the assembler code with gdb (I looked on the Intel i7), you can see that all getInstance() calls involve a jump to the built in double-check lock code for static variable initialization.

In the gist code there is a getInstance() is public for the benchmarking, but simply delete it.

Summary

What we’ve got?

This is a fully functional singleton pattern for your everyday use cases. It fulfills the requirements we need, it is very easy to use and by that it promotes good code usage in our system. Any further improvements we may want to add can fit under the hood of this design.

Previous posts about patterns

Maybe you also want to read about the C++11 generic observer pattern.

That’s all for today,
Have a lovely weekend everyone!

Sagi Zeevi

A software developer brain surgeon … if software only had a brain.
An electronics hobbyist heart surgeon … if electronics only had a heart.

You may also like...

Leave a Reply

Scroll Up