使用boost :: call_once的C ++单例模式

时间:2015-01-07 14:59:30

标签: c++ c++11 boost singleton

C ++中的单身人士(至少之前的C ++ 11 AFAIK)可能是一场噩梦。整个静态初始化顺序惨败。但是boost :: call_once似乎提供了一种实现单例的强大方法。我试图想出一个易于使用的成语,我想分享一些批评意见,希望我没有完全愚蠢:)

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

1 个答案:

答案 0 :(得分:3)

  • 公平地说,我希望call_once是一个特定于线程的特定版本的东西,只需要一个函数本地静态初始化器就可以在c ++ 11中使用:

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

    保证初始化程序不会竞争(在语言规范中)。

    最糟糕的情况是初始化程序抛出时:异常将从Instance()方法传播出来,但下次会尝试再次初始化,因为规范认为变量没有被初始化&#34; 34;初始化表达式抛出时。

  • 如果事实上你需要&#34;需要&#34;一个线程感知的单例(例如每个线程的实例),那么你可能需要thread_local关键字,其语义基本相同。