天天看點

c11 generic singleton

單例模式保證該類對象隻建立一個,且提供全局唯一的通路點。具體實作而言,主要有三個問題:對象初始化,通路和銷毀。

對象初始化。常見的初始化形式有四種:靜态對象成員,靜态指針成員,靜态本地對象,靜态本地指針。對象成員在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;