Skip to content

Several C++ singleton implementations

This article offers some insight into singleton design-pattern.
The singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object. The GoF book describes the singleton as: “Ensure a class only has one instance, and provide a global point of access to it.
The Singleton design pattern is not as simple as it appears at a first look and this is proven by the abundance of Singleton discussions and implementations. That’s way I’m trying to figure a few implementations, some base on C++ 11 features (smart pointers and locking primitives as mutexs). I am starting from, maybe, the most basic singleton implementation trying to figure different weaknesses and tried to add gradually better implementations.
The basic idea of a singleton class implies using a static private instance, a private constructor and an interface method that returns the static instance.

Version 1
Maybe, the most common and simpler approach looks like this:

class simpleSingleton {
  simpleSingleton();
  static simpleSingleton* _pInstance;

public:
  ~simpleSingleton() {}
  static simpleSingleton* getInstance() {
    if (!_pInstance) {
      _pInstance = new simpleSingleton();
    }
    return _pInstance;
  }
  void demo() {
    std::cout << "simple singleton # next - your code ..." << std::endl;
  }
};

simpleSingleton* simpleSingleton::_pInstance = nullptr;

Unfortunately this approach has many issues. Even if the default constructor is private, because the copy constructor and the assignment operator are not defined as private the compiler generates them and the next calls are valid:

// Version 1
simpleSingleton * p = simpleSingleton::getInstance(); // cache instance pointer p->demo();

// Version 2
simpleSingleton::getInstance()->demo();

simpleSingleton ob2(*p); // copy constructor
ob2.demo();

simpleSingleton ob3 = ob2; // copy constructor
ob2.demo();

So we have to define the copy constructor and the assignment operator having private visibility.

Version 2 – Scott Meyers version
Scott Meyers in his Effective C++ book adds a slightly improved version and in the getInstance() method returns a reference instead of a pointer. So the pointer final deleting problem disappears.
One advantage of this solution is that the function-static object is initialized when the control flow is first passing its definition.

class otherSingleton {
  static otherSingleton* pInstance;

  otherSingleton();

  otherSingleton(const otherSingleton& rs) { pInstance = rs.pInstance; }

  otherSingleton& operator=(const otherSingleton& rs) {
    if (this != &rs) {
      pInstance = rs.pInstance;
    }

    return *this;
  }

  ~otherSingleton();

 public:
  static otherSingleton& getInstance() {
    static otherSingleton theInstance;
    pInstance = &theInstance;

    return *pInstance;
  }

  void demo() {
    std::cout << "other singleton # next - your code ..." << std::endl;
  }
};

otherSingleton * otherSingleton::pInstance = nullptr;

The destructor is private in order to prevent clients that hold a pointer to the Singleton object from deleting it accidentally. So, this time a copy object creation is not allowed:

otherSingleton ob = *p;
ob.demo();


error C2248: otherSingleton::otherSingleton ' : cannot access private member declared in class 'otherSingleton'
error C2248: 'otherSingleton::~otherSingleton' : cannot access private member declared in class 'otherSingleton'

but we can still use:

// Version 1
otherSingleton *p = &otherSingleton::getInstance(); // cache instance pointer p->demo();
// Version 2
otherSingleton::getInstance().demo();

This singleton implementation was not thread-safe until the C++ 11 standard. In C++11 the thread-safety initialization and destruction is enforced in the standard.

If you’re sure that your compiler is 100% C++11 compliant then this approach is thread-safe. If you’re not such sure, please use the approach version 4.

Multi-threaded environment
Both implementations are fine in a single-threaded application but in the multi-threaded world things are not as simple as they look. Raymond Chen explains here why C++ statics are not thread safe by default and this behavior is required by the C++ 99 standard.
The shared global resource and normally it is open for race conditions and threading issues. So, the singleton object is not immune to this issue.
Let’s imagine the next situation in a multithreaded application:

static simpleSingleton* getInstance() {
  if (!pInstance)  // 1
  {
    pInstance = new simpleSingleton();  // 2
  }

  return pInstance;  // 3
}

At the very first access a thread call getInstance() and pInstance is null. The thread reaches the second line (2) and is ready to invoke the new operator. It might just happen that the OS scheduler unwittingly interrupts the first thread at this point and passes control to the other thread.
That thread follows the same steps: calls the new operator, assigns pInstance in place, and gets away with it.
After that the first thread resumes, it continues the execution of line 2, so it reassigns pInstance and gets away with it, too.
So now we have two singleton objects instead of one, and one of them will leak for sure. Each thread holds a distinct instance.

An improvement to this situation might be a thread locking mechanism and we have it in the new C++ standard C++ 11. So we don’t need using POSIX or OS threading stuff and now locking getInstance() from Meyers’s implementation looks like:

static otherSingleton& getInstance() {
  std::lock_guard lock(_mutex);
  static otherSingleton theInstance;
  pInstance = &theInstance;
  return *pInstance;
}

The constructor of class std::lock_guard (C++11) locks the mutex, and its destructor unlocks the mutex. While _mutex is locked, other threads that try to lock the same mutex are blocked.
But in this implementation we’re paying for synchronization overhead for each getInstance() call and this is not what we need. Each access of the singleton requires the acquisition of a lock, but in reality we need a lock only when initializing pInstance. If pInstance is called n times during the course of a program run, we need the lock only for the first time.
Writing a C++ singleton 100% thread safe implementation it’s not as simple as it appears as long as for many years C++ had no threading standard support. In order to implement a thread-safe singleton we have to apply the double-checked locking (DCLP) pattern.
The pattern consists of checking before entering the synchronized code, and then check the condition again.
So the first singleton implementation would be rewritten using a temporary object:

static simpleSingleton* getInstance() {
  if (!pInstance) {
    std::lock_guard lock(_mutex);

    if (!pInstance) {
      simpleSingleton* temp = new simpleSingleton;
      pInstance = temp;
    }
  }

  return pInstance;
}

This pattern involves testing pInstance for nullness before trying to acquire a lock and only if the test succeeds the lock is acquired and after that, the test is performed again. The second test is needed for avoiding race conditions in case other thread happens to initialize pInstance between the time pInstance was tested and the time the lock was acquired.
Theoretically, this pattern is correct, but in practice is not always true, especially in multiprocessor environments.
Due to this rearranging of writes, the memory as seen by one processor at a time might look as if the operations are not performed in the correct order by another processor. In our case, the assignment to pInstance performed by a processor might occur before the Singleton object has been fully initialized.
After the first call of getInstance() the implementation with pointers (non-smart) needs pointer to that instance in order to avoid memory leaks.

Version 3 – Singleton with smart pointers
Until C++ 11, the C++ standard didn’t have a threading model and developers needed to use external threading APIs (POSIX or OS dependent primitives). But finally C++ 11 standard has threading support.
Unfortunately, the first C++ new standard implementation in Visual C++ 2010 is incomplete and threading support is available only starting with beta version of VS 2011 or the VS 2012 release preview version.

class smartSingleton {
 private:
  static std::mutex _mutex;

  smartSingleton();
  smartSingleton(const smartSingleton& rs);
  smartSingleton& operator=(const smartSingleton& rs);

 public:
  ~smartSingleton();

  static std::shared_ptr& getInstance() {
    static std::shared_ptr instance = nullptr;

    if (!instance) {
      std::lock_guard lock(_mutex);

      if (!instance) {
        instance.reset(new smartSingleton());
      }
    }

    return instance;
  }

  void demo() {
    std::cout << "smart pointers # next - your code ..." << std::endl;
  }
};

As we know, in C++ by default the class members are private. So, our default constructor is private too. I added here in order to avoid misunderstanding and explicitly adding to public / protected.
Finally, feel free to use your special instance (singleton):

// Version 1
std::shared_ptr p = smartSingleton::getInstance(); // cache instance pointer
p->demo();

// Version 2
std::weak_ptr pw = smartSingleton::getInstance(); // cache instance pointer
pw.lock()->demo();

// Version 3
smartSingleton::getInstance()->demo();

And no memory leaks emotion… 🙂
Multiple threads can simultaneously read and write different std::shared_ptr objects, even when the objects are copies that share ownership.
But even this implementation using double checking pattern but is not optimal to double check each time.


Version 4 – Thread safe singleton C++ 11
To have a thread safe implementation we need to make sure that the class single instance is locked and created only once in a multi-threaded environment.
Fortunately, C++ 11 comes in our help with two new entities: std::call_once and std::once_flag. Using them with a standard compiler we have the guaranty that our singleton is thread safely and no memory leak.
Invocations of std::call_once on the same std::once_flag object are serialized.
Instances of std::once_flag are used with std::call_once to ensure that a particular function is called exactly once, even if multiple threads invoke the call concurrently.
Instances of std::once_flag are neither CopyConstructible, CopyAssignable, MoveConstructible nor MoveAssignable.

Here it is my proposal for a singleton thread safe implementation in C++ 11:

class safeSingleton {
  static std::shared_ptr<safeSingleton> instance_;
  static std::once_flag only_one;

  safeSingleton(int id) {
    std::cout << "safeSingleton::Singleton()" << id << std::endl;
  }

  safeSingleton(const safeSingleton& rs) { instance_ = rs.instance_; }

  safeSingleton& operator=(const safeSingleton& rs) {
    if (this != &rs) {
      instance_ = rs.instance_;
    }

    return *this;
  }

 public:
  ~safeSingleton() { std::cout << "Singleton::~Singleton" << std::endl; }

  static safeSingleton& getInstance(int id) {
    std::call_once(
        safeSingleton::only_one,
        [](int idx) {
          safeSingleton::instance_.reset(new safeSingleton(idx));

          std::cout << "safeSingleton::create_singleton_() | thread id " + idx
                    << std::endl;
        },
        id);

    return *safeSingleton::instance_;
  }

  void demo(int id) {
    std::cout << "demo stuff from thread id " << id << std::endl;
  }
};

std::once_flag safeSingleton::only_one;
std::shared_ptr<safeSingleton> safeSingleton::instance_ = nullptr;

The parameter to getInstance() was added for demo reasons only and should be passed to a new proper constructor. As you can see, I am using a lambda instead normal method.
This is how I tested my safeSingleton and smartSingleton classes.

std::vector v;
int num = 20;

for (int n = 0; n < num; ++n) {
  v.push_back(
      std::thread([](int id) { safeSingleton::getInstance(id).demo(id); }, n));
}

std::for_each(v.begin(), v.end(), std::mem_fn(&std::thread::join));

// Version 1
std::shared_ptr<smartSingleton> p = smartSingleton::getInstance(
    1);  // cache instance pointer p->demo("demo 1");

// Version 2
std::weak_ptr<smartSingleton> pw = smartSingleton::getInstance(2);  // cache instance pointer
pw.lock()->demo(2);

// Version 3
smartSingleton::getInstance(3)->demo(3);

So I create 20 threads and I launch them in parallel (std::thread::join) and each thread accesses getInstance() (with a demo id parameter). Only one of the threads that is trying to create the instance succeeds.
Additionally, if you’re using a C++11 100% compiler you could also delete the copy constructor and assignment operator. This will allow you to obtain an error while trying to use such deleted members.

Other comments
I tested this implementation on a machine with Intel i5 processor (4 cores). If you see some concurrent issues in this implementation please fell free to share here. I am open to other good implementations, too.
An alternative to this approach is creating the singleton instance of a class in the main thread and pass it to the objects which require it. In case we have many singleton objects this approach is not so nice because the objects discrepancies can be bundled into a single ‘Context’ object which is then passed around where necessary.

Update: According to Boris’s observation I removed std::mutex instance from safeSingleton class. This is not necessary anymore because std::call_once is enough to have thread safe behavior for this class.

Update2: According to Ervin and Remus’s observation, in order to make things clear I simplified the implementation version 3 and this is not using std::weak_ptr anymore.

References:
just::thread – Anthony Williams – Just Software Solutions Ltd
C++ and the Perils of Double-Checked Locking by Scott Meyers and Andrei Alexandrescu
Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu

Silviu Ardelean

Software Engineer

More Posts - Website

Follow Me:
TwitterFacebookPinterest

30 thoughts on “Several C++ singleton implementations”

  1. If you want to make your class non copyable don’t just make the operator= and copy constructor private, make them unimplemented (so you get link failures if friends or the class itself instantiate them), or better yet, make them =delete’d. Your copy constructor and assignment operator are broken anyway as they try to copy static members.

    Also, as long as you are using function statics (whose initialization is thread safe in C++11 and can be implemented optimally), there is no reason to have a class static pInstance;

    This is the minimal and probably most efficient singleton in C++11

    class Singleton
    {
    Singleton(Singletion&) = delete;
    void operator=(Singleton&) = delete;
    public:
    static Singleton& GetInstance() {
    static GetInstance instance_{}; // threadsafe initialization
    return instance_;
    }
    }
    private:
    ~Singleton(){}

    };

    1. Giovanni, thank you very much for this proposal. Indeed it’s a minimal implementation and it looks interesting making those methods “=delete”. That’s one reason why C++ 11 is nice.
      As an additional comment I suppose that your solution returns Singleton instance (or reference to) instead of GetInstance.

  2. What is a reason to use call_once and mutex simultaneously ?
    Another question: is there any thread-unsafe problem in Giovanni Deretta’s code (I can’t see any) ?

    1. Boris, related to the first question, this is a very good observation. Thank you!
      Indeed, using mutex after call_once it’s not absolutely necessary anymore. call_once is enough.

      For the second question, I am sorry, I don’t.
      As I told in article I invite you to share any comments related to my implementations but I’m open to approve comments with other good implementations, too.

  3. How can a copy constructor receive as it’s parameter the same object ? The object isn’t constructed yet. Because this is what I get looking at this code :
    otherSingleton(const otherSingleton& rs) {
    if (this != &rs) {
    pInstance = rs.pInstance;
    }
    }

    I’m going to call this “The Chuck Norris Pattern”, if nobody objects.

  4. Copy constructor’s “if” test is a good observation, but it’s an insignificant issue. This additional test it’s mandatory only for assign operator. And don’t forget: this condition is never tested because that copy constructor is private.

    If you want to call that “pattern” I have no objection. But, don’t forget: the only pattern Chuck Norris knows is God Object.

  5. When i have tested last shared_ptr version in visual studio 2012, i got leak message in debug mode.
    I think that static shared ptr causes leak.
    Can you give me any advice?

    1. The implementation of shared_ptr is based on the reference-counting model.
      Using it incorrectly might cause memory leaks. For better understanding, please search more about “shared_ptr circular dependency” or “shared_ptr circular reference”.
      I recommend you using std::weak_ptr each time you have a non-owning reference to an object that is managed by std::shared_ptr.

      Please take a look here, too: “The problem is that, if you lose reference to the topmost node, then the topmost node still holds strong references to its children, and all its children also hold a strong reference to their parents.

  6. Nice blog. This following line is a buggy code and VS10, VS11 beta can’t compile your Version-3 code.

    std::weak_ptr smartSingleton:: thisObjPtr = nullptr;

    weak_ptr does not have to be nulled. Can you please fix the code and give me a solution? I appriate your cooperation.

    1. The 3nd version is impossible to run on VS 2010 because mutex header is not available in VC++ 2010 (only with the VS 2011 beta – the version that I used when I wrote this article).
      So if you still want to use that implementation in VS 2010 without thread safe support then please just remove the initialization of weak pointer with nullptr and call that declaration in the .cpp file.
      std::weak_ptr< smartSingleton > smartSingleton::thisObjPtr;

  7. What I dislike in the 4th version is the fact that you have a public dtor.
    I am aware that you need either that to allow shared ptr to be able to delete it or make a friend class std::default_delete so you be able to call a less than public dtor.

    Why didn’t you use a unique_ptr anyway as you don’t expose shared_ptr anyway?

    Regards,
    Sam

  8. Sam, thank you for you observation. Maybe I was not the best inspirited with std::shared_ptr. We can use std::unique_ptr also, but in that cause would be recommended to implement move constructor and move operator. This is just a sample that can be extended and modified.
    Anyhow, having no possibility to “copy” the singleton instance our std::shared_ptr’s reference counter stays at 1. So, if we want we can call it “unique”. 🙂

  9. I’m wondering about the static weak_ptr that you use in the 3rd version. What is it accomplishing when you only call lock on it once when you first access the singleton and then just keep a static shared_ptr after that?

    Thanks!

    1. Pran, sorry, bad news! In case you don’t have a C++11 compiler then most probably you don’t have smart pointers (out of deprecated std::auto_ptr) and std::call_once. So, you can use only the first two versions and your singleton will not be a thread safe one. In order to created a so call “singleton thread safe” (I would not call it in that way in this case) you might use OS mutex primitives. But in that way you, depending on your application complexity, you may encounter some additional blocks or even worser – dead-locks.

  10. I have ‘few’ observation about the code you produced here:

    1. having a copy constructor and assigment operator is in contrast with what you stated at the beginning : “… singleton pattern … by restricting the instantiation of a class to one object”. Even when they are private.

    2. The code:
    otherSingleton& operator = (const otherSingleton& rs) {
    if (this != &rs) {
    pInstance = rs.pInstance;
    }

    return *this;
    }

    is same as:
    otherSingleton& operator = (const otherSingleton& rs) {
    if (this != &rs) {
    pInstance = pInstance;
    }

    return *this;
    }
    so, all it does is to prevent the unnecessary “var = var” operation.

    3. what is the purpose of
    static otherSingleton * pInstance;
    variable? It is used for real only in
    static otherSingleton& getInstance()
    {
    static otherSingleton theInstance;
    pInstance = &theInstance;

    return *pInstance;
    }
    which could very easily [re]written as
    static otherSingleton& getInstance()
    {
    static otherSingleton theInstance;

    return theInstance;
    }

    4. returning a pointer, in this [particular] case is confusing. This, because [almost] always the receiver manages its life. So, the question/doubt “should it be freed after usage or not” is present?
    in your case:
    static simpleSingleton* getInstance() {…. }
    simpleSingleton *p = simpleSingleton::getInstance();
    delete p; //This is an EXTREMELY BAD idea
    but, in a similar case:
    auto p = new…..;
    do_something( p );
    delete p; // This is necessary

    5. the line:
    static std::shared_ptr instance = thisObjPtr.lock();
    has same effect as
    static std::shared_ptr instance;
    because it is executed only ONCE, and initial value of the week_ptr is nullptr.
    This observation was made by Erin too.
    So, your weak_ptr variable is useless. The static variable called ‘instance’ will be used in all cases. So, you use it only to init with null a shared_ptr. Useless thing, this is done by default by its constructor.

    6. The code
    otherSingleton *p = & otherSingleton::getInstance(); // cache instance pointer
    p->demo();
    is more clear as:
    otherSingleton &p = otherSingleton::getInstance(); // cache instance pointer
    p.demo();
    There is no advantage to get the address of a variable only to dereference it after.

    1. I think we can write a book by philosophizing on this idiom, about pros and cons different implementations. 🙂
      Maybe I was not very clear from the beginning by the proposal of my article and I am trying to make it a bit clear by this message. I started from, maybe, the most basic singleton implementation trying to figure different weaknesses and adding implementations with improvements gradually.

      1. There is an important difference by having copy constructor and assignment operator private vs public. The first version demonstrate what might happens without private.
      2. This part of code will never be executed as long as this assignment operator will be private. If you want we can write it simpler…
      otherSingleton& operator = (const otherSingleton& rs);
      But if we would not talk about a singleton class and that operator would be public/protected, I think you admit this is a very bad thing.
      if (this != &rs) {
      pInstance = pInstance;
      }

      3. You got the point.
      4. Absolutely the first version is the worsted approach. Thank you for completing me with this weak point.
      5. Yes, we can simplify that implementation without using std::weak_ptr. In order to make things clear, I did the update.
      6. This is just a demo. I prefer using cache instance pointers instead of such long calls.
      p->demo();
      //instead of
      otherSingleton::getInstance()->demo();

  11. This is using a Double-Checked Locking Pattern similar to Version 3 of yours. If you want to investigate the reasons for using Volatile equiv and thread fences… here you go. **untested**

    ————————————————

    class smartSingleton {
    private:
    static std::atomic<std::shared_ptr> _instance;
    static std::mutex _mutex;

    smartSingleton() {}
    smartSingleton(smartSingleton const&) = delete; // Don’t Implement
    void operator = (smartSingleton const&) = delete; // Don’t implement

    public:
    static std::shared_ptr& getInstance();
    };

    std::shared_ptr& smartSingleton::getInstance()
    {
    // Use DCLP for multi-CPU.
    std::shared_ptr &tmp = _instance.load(std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);
    if (tmp == nullptr) {
    std::lock_guard lock(_mutex);
    tmp = _instance.load(std::memory_order_relaxed);
    if (tmp == nullptr) {
    tmp.reset(new smartSingleton());
    std::atomic_thread_fence(std::memory_order_release);
    _instance.store(tmp, std::memory_order_relaxed);
    }
    }
    return tmp;
    }

  12. Very interesting thanks. I noticed the text refers to “the C++ 99” standard, which looks like a typo 🙂

  13. Pingback: Singleton in c++ different way of creation | diigopost

  14. Pingback: LintCode 204: Singleton (Easy) | helloyuan

  15. Hi Silviu,
    For code
    static otherSingleton& getInstance()
    {
    std::lock_guard lock(_mutex);
    static otherSingleton theInstance;
    pInstance = &theInstance;
    return *pInstance;
    }
    if i am not wrong C++11, scoped static initialization is now thread-safe. so below code should be thread safe if we are using C++11

    static otherSingleton& getInstance()
    {
    static otherSingleton theInstance;
    return otherSingleton
    }

  16. Pingback: Research on Singletons – Records and Thoughts

  17. Thread-safe shared singleton with lazy constructor and RAII destructor.
    Any criticism are welcome.

    class safeSingleton {
    private:
    static std::mutex _mutex;
    static std::weak_ptr _instance;

    safeSingleton() = default;
    safeSingleton( const safeSingleton & ) = delete;
    safeSingleton( safeSingleton && ) = delete;
    safeSingleton &operator=( const safeSingleton & ) = delete;
    safeSingleton &operator=( safeSingleton && ) = delete;

    public:
    static std::shared_ptr getInstance() {
    if ( std::shared_ptr existingCopy = _instance.lock() ) {
    return existingCopy;
    } else {
    std::lock_guard lock( _mutex );
    std::shared_ptr newCopy = _instance.lock();
    if ( !newCopy ) {
    newCopy.reset( new safeSingleton() );
    _instance = newCopy;
    }
    return newCopy;
    }
    }
    };

    std::weak_ptr safeSingleton::_instance;
    std::mutex safeSingleton::_mutex;

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.