单例模式保证该类对象只创建一个,且提供全局唯一的访问点。具体实现而言,主要有三个问题:对象初始化,访问和销毁。
对象初始化。常见的初始化形式有四种:静态对象成员,静态指针成员,静态本地对象,静态本地指针。对象成员在main函数之前就已经初始化了,不能使用任何系统启动才加载的配置项;而指针成员同理,但可以实现延迟实例化。这两种形式在多线程情况下,都需要加锁进行实例化(从语法上,静态成员对象能保证对象唯一性吗?),从而防止产生多个副本。对于本地变量,在第一次访问该静态方法时,进行初始化,要求该对象必须是is_default_constructible,且c11从语法上保证其并发情况的下的唯一性。而对于本地指针,则可以进行定制化的初始化,但同时也要求通过锁进行并发控制,反之创建多个副本。因此本地对象优于成员对象,因为有并发保证,而且可以延迟初始化;而当对象初始化和访问在不同的方式里面时,指针成员优于本地变量,因为静态本地变量不能提供跨方法访问。所以,初始化代码如下:
// default constructible type
Tp& Instance() { static Tp s_instance; return s_instance;}
// non-default constructible type
template<class... Args>
Tp& Instance(Args&& args...) {
std::call_once( s_init_once_flag, [&](){
s_pInstance = std::unique_ptr<Tp>(new Tp(std::forward<Args>(args)...)); } );
return *s_pInstance;
}
对象访问。对于default constructible type,自然通过Instance()访问;而对于non-default constructible type既可以通过初始化的Instance(args...)也可以通过Instance()来访问。
对象销毁。对于default constructible type,系统exit的时候会自动销毁静态本地变量;对于non-default constructible type则由unique_ptr来保证销毁。
template
class Singleton : public Noncopyable
{
public:
static Tp& Instance()
{
// 1>c11 guarantees that a local static variable is only run once
// this ensures thread-safety in initializing singletion class
// in concurrecy context
// 2>it won't init unless it's first accessed
// 3>if g_instance works as a static member variable
// it will be inited before main, which means
// its initialization can't take advantage of
// info known only once the program is up and running
// ### it's unnecessary to be zero-argument default constructed
// ### it should support various constructor
static Tp s_instance;
return s_instance;
}
// noncopyable
// Singleton
& operator=( const Singleton
& ) = delete;
// Singleton( const Singleton
&) = delete;
protected:
// if a class supports singleton, it has to inherit class Singleton
Singleton(){};
virtual ~Singleton(){};
};
template
class Singleton
: public Noncopyable { public: template
static Tp& Instance(Args&&... args) { std::call_once( s_inited_once_flag, [&](){ s_pInstance = std::unique_ptr
( new Tp(std::forward
(args)... ) ); // std::atexit(destroy); }); return *s_pInstance; } static Tp& Instance() { if( nullptr == s_pInstance ) { throw std::logic_error(std::string() + typeid(Tp).name() + " is not inited!\n"); } return *s_pInstance; } // noncopyable // Singleton
& operator=( const Singleton
& ) = delete; // Singleton( const Singleton
&) = delete; protected: // if a class supports singleton, it has to inherit class Singleton Singleton(){}; virtual ~Singleton(){}; private: static std::unique_ptr
s_pInstance; static std::once_flag s_inited_once_flag; /* static void destroy() { if( nullptr != s_pInstance ) { delete s_pInstance; s_pInstance = nullptr; std::cout << typeid(Tp).name() << " get deleted in " << __PRETTY_FUNCTION__ << '\n'; } } */ }; template
std::unique_ptr
Singleton
::s_pInstance; template
std::once_flag Singleton
::s_inited_once_flag;