flux
flux

Reputation: 199

C++ singleton pattern using boost::call_once

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;
}

Upvotes: 2

Views: 3719

Answers (1)

sehe
sehe

Reputation: 393487

  • To be fair, I expect that call_once is a threading specific version of something that can already been had in c++11 using just a function local static initializer:

    template< class T >
    T& Singleton<T>::Instance()
    {
        static bool const init = [] () -> bool { Init(); return true; }();
    
        return *s_instance;
    }
    

    The initializer is guaranteed not to race (in the language specification).

    Worst case behaviour is when the initializer throws: the exception will propagate out of the Instance() method but next time will try to initialize again, because the specification deems the variable to have "not been initialized" when the initializer expression throws.

  • If in fact you "need" a thread-aware singleton (e.g. instance per thread), then you may want the thread_local keyword, with largely the same semantics.

Upvotes: 4

Related Questions