Singletons in C++ (at least prior C++11 AFAIK) can be a nightmare. With the whole static initialisation order fiasco. But boost::call_once seems to offer a robust way to implement singletons. I've tried to come up with an easy to use idiom I'd like to share for some critical feedback, hope I haven't been completely foolish :)
// Usage:
// You can make anything with a public or protected ctor a singleton.
//
// class A
// {
// public:
// ~A();
// public:
// // Optional, shorter to type
// static A& Instance() { return Singleton<A>::Instance(); }
// void foo();
//
// protected:
// explicit A(); // Can't be private, but can be public, protected is recommended.
// };
//
// Singleton<A>::Instance().foo();
// A::Instance().foo();
//
template< class T >
class Singleton : public T // inerits from T so we can access the protected constructor.
{
public:
virtual ~Singleton() {}
public:
static T& Instance();
private:
static boost::once_flag s_onceFlag;
// We use a raw pointer to avoid dynamic initialisation. If something that
// has a constructor (eg, shared_ptr ) then the dynamically initialised ctor
// may get called after the call once function is called (if the call once function
// is statically invoked before main). Then the instance pointer will be overwritten.
// Using a zero initialised pointer avoids this problem.
static T* s_instance;
private:
static void Init();
private:
explicit Singleton() {} // Used only to allow access to the protected ctor in base.
};
template< class T >
boost::once_flag Singleton<T>::s_onceFlag = BOOST_ONCE_INIT; // zero initialised variable, no order o initialisation shananigans
template< class T >
T* Singleton<T>::s_instance = 0;
template< class T >
void Singleton<T>::Init()
{
static Singleton<T> instance; // static local variable is thread safe since this function is called once only.
s_instance = &instance;
}
template< class T >
T& Singleton<T>::Instance()
{
boost::call_once( s_onceFlag, Init );
return *s_instance;
}
Aucun commentaire:
Enregistrer un commentaire