#pragma once ///////////////////////////////////////////////////////////////////// // SingletonBase.h - base class for useful Singletons // // Ver 2.0 // // Jim Fawcett, CSE776 - Design Patterns, Fall 2017 // ///////////////////////////////////////////////////////////////////// /* * Ver 2.0 : 13 Sep 2017 * - Removed an incorrect form of double-check locking. Will explore * further in the next version. * Ver 1.0 : 11 Sep 2017 * - first release */ /* * - SingletonBase is templatized on a Locking class. If application * is single-threaded, then use a NoLock class. See cpp file for * an example. * - Note that this base has no operations nor shared data */ #include "../Utilities/Utilities.h" #include #include namespace Singleton { Utilities::Log log; template class SingletonBase { public: static SingletonBase* Instance(); virtual void Release(); protected: static SingletonBase* pInstance; static size_t refCount; SingletonBase(); virtual ~SingletonBase(); SingletonBase(const SingletonBase& sb); }; template SingletonBase* SingletonBase::pInstance = nullptr; template size_t SingletonBase::refCount = 0; template SingletonBase::SingletonBase() { log.doLog("\n creating instance of SingletonBase"); } template SingletonBase::SingletonBase(const SingletonBase& sb) { pInstance = sb.pInstance; refCount = sb.refCount; } template SingletonBase::~SingletonBase() { log.doLog("\n destroying instance of SingletonBase"); } /*---< thread safe lazy initialization >-------------------------*/ /* * - Using double check locking (DCL) avoids taking locks after initialization. * - DCL now works in Java and C# applications if you declare pInstance volatile. * but, does not work in C++ without some fancy footwork. I will explore that * in the next version. * https://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html * https://www.ibm.com/developerworks/library/j-jtp03304/index.html * http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ */ template SingletonBase* SingletonBase::Instance() { ++refCount; log.doLog("\n retrieving reference"); //if (pInstance == nullptr) // this simple form of double-check locking doesn't work //{ // for C++, will explore this issue in next version. // assume that lock() acquires lock, ~lock() releases lock //{ Lock lock; if (pInstance == nullptr) { pInstance = new SingletonBase(); } //} //} return pInstance; } template void SingletonBase::Release() { log.doLog("\n decrementing reference count"); Lock lock; if (--refCount == 0) { delete pInstance; pInstance = nullptr; } } }