But still, the singleton is a viable pattern in terms of software design. Just because you cannot build it with the tools at hand does not necessarily make it a bad pattern. With C++11 it is possible to get rid of some mayor drawbacks implementation wise. Let's first have a look at the implementation we came up with at Xcessity.
Implementation
Header File:
#include <memory>
#include <mutex>
class CSingleton
{
public:
virtual ~CSingleton();
static CSingleton& getInstance();
static void destroyInstance();
private:
static std::unique_ptr<CSignleton> mInstance;
static std::once_flag mOnceFlag;
CSingleton();
CSingleton(const CSingleton&);
CSingleton& operator=(const CSingleton&);
#ifdef _UNITTESTpublic:
static void reset() { mInstance.reset(new DeviceManager); }
#endif
std::vector<SomeClass> mPrivateCollection;
};
Source File:std::unique_ptr<CSingleton> CSingleton::mInstance = nullptr;
std::once_flag CSingleton::mOnceFlag;
CSingleton& CSingleton::getInstance()
{
std::call_once(mOnceFlag,
[] { mInstance.reset(new CSingleton); });
return *mInstance.get();
}
void CSingleton::destroyInstance()
{
mInstance.reset();
}
Explanation
This implementation is inspired by Marc Gregoire's post on "Implementing a Thread-safe Singleton with C++". You can follow the link to read more about the basic implementation. Let's look at the added features.
CSingleton::destroyInstance()
You may be aware of the more common approach to create the singleton instance by using a static variable. The benefit of the pointer based approach is that you can choose when the singleton get's destroyed at the end of your application. Sometimes it is desirable to choose the exact order in which your components get destroyed. Of course you have to ensure that nothing else accesses the singleton during or after this call. Typically you want to do this at the end of runtime with only the main thread active.
Additionally the
unique_ptr
will take care of deleting the singleton object in case you don't care about the order of deconstruction. So even if you don't call destroyInstance()
the singleton gets properly deleted.#ifdef, #endif
One argument against singletons is that they are hard to test using unittests. In unittesting you try to test one method after another in separate tests. The problem arising is that each test performs its operations on the same singleton object. So whenever a test alters the state of the singleton it is propagated to the following tests. This may lead to undesired behavior and can lead to false testing results.
Using
reset()
at the beginning of every unittest solves this issue. In each test you get a nice and clean singleton object ready for testing. By defining _UNITTEST
in your test build environment this method only get's exposed for testing purposes.#ifdef & public:
In unittesting it is beneficial to test only single methods. Of course it is important to use the public interfaces. Ultimately you want to call the method and check if the invariant of the object is as promised by the method. Having access to the private members gives you the chance to check these conditions. Many approaches exist to achieve this behavior, but this is one of the least intrusive ones.
It is important not to include the static members in your public section for unittesting. It would cause linker errors to make the static members public just in the header files when using a static library for example.
Conclusion
With this implementation we can solve the following issues of the singleton pattern:- thread-safety
- random deconstruction order
- unittesting a singleton
- access to private members for unittesting
Hopefully you found some inspiration in this implementation. Any suggestions on improvements are welcome.