C++11 generic singleton pattern

by Sagi Zeevi ·
Published October 28, 2017
· Updated November 15, 2017

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

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:

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:

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.

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.