Implementing a Thread-safe Singleton with C++11

C++11 makes it easier to write a thread-safe singleton. Here is an example. The class definition of the singleton looks as follows:

#include <memory>
#include <mutex>

class CSingleton
{
public:
	virtual ~CSingleton() = default;
	static CSingleton& GetInstance();

private:
	static std::unique_ptr<CSingleton> m_instance;
	static std::once_flag m_onceFlag;
	CSingleton() = default;
	CSingleton(const CSingleton& src) = delete;
	CSingleton& operator=(const CSingleton& rhs) = delete;
};

The implementation of the GetInstance() method is very easy using C++11 std::call_once() and a lambda:

std::unique_ptr<CSingleton> CSingleton::m_instance;
std::once_flag CSingleton::m_onceFlag;

CSingleton& CSingleton::GetInstance()
{
	std::call_once(m_onceFlag,
		[] {
			m_instance.reset(new CSingleton);
	});
	return *m_instance.get();
}
Share

15 Comments so far »

  1. Sudo said,

    Wrote on October 21, 2012 @ 9:54 pm

    In C++11 thread-safety initialization and destruction is enforced in the standard. You don’t need to make use of std::once_flag or even std::unique_ptr.

  2. Marc Gregoire said,

    Wrote on October 22, 2012 @ 7:39 am

    If your compiler is 100% C++11 compliant, then you are correct. However, that is currently not yet the case. Take for example GCC, if you look on this page ( http://gcc.gnu.org/projects/cxx0x.html ) you can see that they don’t yet support the concurrency memory model and don’t yet support the “Dynamic Initialization and Destruction with Concurrency”, among other features.
    If you are absolutely sure your compiler supports those things, then you don’t need the call_once.
    However, if you are not 100% sure, I think it’s safer to use the call_once construct. If that compiles, then you know it will be thread-safe, unlike when you assume your compiler supports the new memory model, but it doesn’t, then you will introduce subtle multi-threading bugs.

  3. sellibitze said,

    Wrote on October 22, 2012 @ 9:13 am

    The singleton object may be destroyed to early. Consider a second singleton from another translation unit that makes use of this one even in its destructor. The deinitialization order of the static unique_ptr objects holding the singleton object adresses is unspecified.

  4. C said,

    Wrote on October 22, 2012 @ 8:17 pm

    I really like the choice for the std::once_flag flag. Will there be any support in C++11 for std::twice_flag flags etc?

  5. Marc Gregoire said,

    Wrote on October 22, 2012 @ 9:50 pm

    I’ve heard nothing about things like std::twice_flag.

    I’m wondering though, what are your use-cases for something like std::twice_flag?

  6. Francisco Almeida said,

    Wrote on October 23, 2012 @ 5:42 pm

    Since we’re using C++11 in the example, you could also delete the copy constructor and assignment operator. The compiler error obtained when trying to use a deleted member is a bit more expressive than when using a private member.

  7. Marc Gregoire said,

    Wrote on October 23, 2012 @ 5:53 pm

    100% correct about using the “delete” specifier on the copy constructor and the assignment operator.
    GCC does support it, but unfortunately, Visual C++ doesn’t support that feature yet, so I didn’t use it in this example.

  8. Adam said,

    Wrote on August 26, 2014 @ 2:56 am

    This is great! Thank you for sharing. I had been struggling on using mutex to ensure the getInstance thread safety yet kept failing due to what is stated in this paper: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

    seems like on multi-processor machine we will have deal with a long of architecture and compiler macro stuffs to do the job if we don’t use c++11 features.

  9. Viktor said,

    Wrote on May 20, 2016 @ 5:22 pm

    Why do you declare destructor of this CSingleton as virtual?
    How would one inherit from signleton, if the constructor is private?
    In this case destructor may also be private, I suppose.

  10. yantaosong said,

    Wrote on August 18, 2016 @ 7:32 am

    g++ singleton.cpp -o singleton -lstdc++ -std=c++11

    /tmp/ccjiNxTG.o: In function `CSingleton::GetInstance()::{lambda()#1}::operator()() const’:
    singleton.cpp:(.text+0x78): undefined reference to `CSingleton::CSingleton()’
    collect2: error: ld returned 1 exit status

  11. yantaosong said,

    Wrote on August 18, 2016 @ 8:05 am

    i am sorry for last comment. and i met another error while run ti .

    (gdb)
    std::call_once<CSingleton::GetInstance():: >(std::once_flag &, ) (__once=…,
    __f=)
    at /usr/include/c++/6.1.1/mutex:608
    608 std::forward(__args)…);

  12. yantaosong said,

    Wrote on August 18, 2016 @ 1:23 pm

    more for that

    CSingleton(const CSingleton& src) = delete;
    CSingleton& operator=(const CSingleton& rhs) = delete;

    I think this two method is not useful for this class , is it ?

  13. Carlos Alce said,

    Wrote on November 17, 2016 @ 5:48 pm

    Thanks for posting this solution!
    It would be possible for someone to help me with the main() implementation?
    I have problems with the right way to call GetInstance():

    CSingleton singleton = CSingleton::GetInstance(); Error received: error: calling a private constructor of class ‘CSingleton’.

    CSingleton& singleton = CSingleton::GetInstance(); this time the error points to line # 8, of GetInstance() implementation (inside the lambda, following the line numbers as shown in your code here above):
    m_instance.reset(new CSingleton). Error received: undefined reference to `CSingleton::CSingleton()’

    And other options with similar results.
    Thanks in advance for your help!
    CA

  14. Marc Gregoire said,

    Wrote on August 10, 2017 @ 12:59 pm

    You can indeed delete the copy constructor and copy assignment operator.

  15. Marc Gregoire said,

    Wrote on August 10, 2017 @ 1:05 pm

    Sorry, I only showed the implementation of GetInstance().
    I didn’t include the code for the destructor, and the default constructor, since those were trivial.

    I have now modified the code in the article, now the destructor and the default constructor are defaulted, and the copy constructor and copy assignment operator are deleted.

Comment RSS · TrackBack URI

Leave a Comment

Name: (Required)

E-mail: (Required)

Website:

Comment: