C++完美实现Singleton模式
Singleton模式是常用的设计模式之一,但是要实现一个真正实用的设计模式却也不是件容易的事情。
标准的实现
1 class Singleton 2 { 3 public: 4 static Singleton * Instance() 5 { 6 if( 0== _instance) 7 { 8 _instance = new Singleton; 9 } 10 return _instance; 11 } 12 protected: 13 Singleton(void) 14 { 15 } 16 virtual ~Singleton(void) 17 { 18 } 19 static Singleton* _instance; 20 };
这是教科书上使用的方法。看起来没有什么问题,其实包含很多的问题。下面我们一个一个的解决。
问题一 自动垃圾回收
上面的程序必须记住在程序结束的时候,释放内存。为了让它自动的释放内存,我们引入auto_ptr改变它。
1 #include <memory> 2 #include <iostream> 3 using namespace std; 4 class Singleton 5 { 6 public: 7 static Singleton * Instance() 8 { 9 if( 0== _instance.get()) 10 { 11 _instance.reset( new Singleton); 12 } 13 return _instance.get(); 14 } 15 protected: 16 Singleton(void) 17 { 18 cout <<"Create Singleton"<<endl; 19 } 20 virtual ~Singleton(void) 21 { 22 cout << "Destroy Singleton"<<endl; 23 } 24 friend class auto_ptr<Singleton>; 25 static auto_ptr<Singleton> _instance; 26 }; 27 //Singleton.cpp 28 auto_ptr<Singleton> Singleton::_instance;
问题二 增加模板
在我的一个工程中,有多个的Singleton类,对Singleton类,我都要实现上面这一切,这让我觉得烦死了。于是我想到了模板来完成这些重
复的工作。
现在我们要添加本文中最吸引人单件实现:
1 #include <memory> 2 using namespace std; 3 using namespace C2217::Win32; 4 5 namespace C2217 6 { 7 namespace Pattern 8 { 9 template <class T> 10 class Singleton 11 { 12 public: 13 static inline T* instance(); 14 15 private: 16 Singleton(void){} 17 ~Singleton(void){} 18 Singleton(const Singleton&){} 19 Singleton & operator= (const Singleton &){} 20 21 static auto_ptr<T> _instance; 22 }; 23 24 template <class T> 25 auto_ptr<T> Singleton<T>::_instance; 26 27 template <class T> 28 inline T* Singleton<T>::instance() 29 { 30 if( 0== _instance.get()) 31 { 32 _instance.reset ( new T); 33 } 34 35 return _instance.get(); 36 } 37 38 //Class that will implement the singleton mode, 39 //must use the macro in it's delare file 40 #define DECLARE_SINGLETON_CLASS( type ) \ 41 friend class auto_ptr< type >;\ 42 friend class Singleton< type >; 43 } 44 }
问题三 线程安全
上面的程序可以适应单线程的程序。但是如果把它用到多线程的程序就会发生问题。主要的问题在于同时执行_instance.reset ( new T);
就会同时产生两个新的对象,然后马上释放一个,这跟Singleton模式的本意不符。所以,你需要更加安全的版本:
1 #include <memory> 2 using namespace std; 3 #include "Interlocked.h" 4 using namespace C2217::Win32; 5 6 namespace C2217 7 { 8 namespace Pattern 9 { 10 template <class T> 11 class Singleton 12 { 13 public: 14 static inline T* instance(); 15 16 private: 17 Singleton(void){} 18 ~Singleton(void){} 19 Singleton(const Singleton&){} 20 Singleton & operator= (const Singleton &){} 21 22 static auto_ptr<T> _instance; 23 static CResGuard _rs; 24 }; 25 26 template <class T> 27 auto_ptr<T> Singleton<T>::_instance; 28 29 template <class T> 30 CResGuard Singleton<T>::_rs; 31 32 template <class T> 33 inline T* Singleton<T>::instance() 34 { 35 if( 0 == _instance.get() ) 36 { 37 CResGuard::CGuard gd(_rs); 38 if( 0== _instance.get()) 39 { 40 _instance.reset ( new T); 41 } 42 } 43 return _instance.get(); 44 } 45 46 //Class that will implement the singleton mode, 47 //must use the macro in it's delare file 48 #define DECLARE_SINGLETON_CLASS( type ) \ 49 friend class auto_ptr< type >;\ 50 friend class Singleton< type >; 51 } 52 } CresGuard 类主要的功能是线程访问同步,代码如下: 1 class CResGuard { 2 public: 3 CResGuard() { m_lGrdCnt = 0; InitializeCriticalSection(&m_cs); } 4 ~CResGuard() { DeleteCriticalSection(&m_cs); } 5 6 // IsGuarded is used for debugging 7 BOOL IsGuarded() const { return(m_lGrdCnt > 0); } 8 9 public: 10 class CGuard { 11 public: 12 CGuard(CResGuard& rg) : m_rg(rg) { m_rg.Guard(); }; 13 ~CGuard() { m_rg.Unguard(); } 14 15 private: 16 CResGuard& m_rg; 17 }; 18 19 private: 20 void Guard() { EnterCriticalSection(&m_cs); m_lGrdCnt++; } 21 void Unguard() { m_lGrdCnt--; LeaveCriticalSection(&m_cs); } 22 23 // Guard/Unguard can only be accessed by the nested CGuard class. 24 friend class CResGuard::CGuard; 25 26 private: 27 CRITICAL_SECTION m_cs; 28 long m_lGrdCnt; // # of EnterCriticalSection calls 29 };
问题四 实用方法
比如你有一个需要实现单件模式的类,就应该这样实现:
1 #include "singleton.h" 2 using namespace C2217::Pattern; 3 4 class ServiceManger 5 { 6 public: 7 void Run() 8 { 9 } 10 private: 11 ServiceManger(void) 12 { 13 } 14 virtual ~ServiceManger(void) 15 { 16 } 17 DECLARE_SINGLETON_CLASS(ServiceManger); 18 }; 19 20 typedef Singleton<ServiceManger> SSManger;
在使用的时候很简单,跟一般的Singleton实现的方法没有什么不同。
1 int _tmain(int argc, _TCHAR* argv[]) 2 { 3 SSManger::instance()->Run(); 4 }
一个简单的Singleton模式的实现,可以看到C++语言背后隐藏的丰富的语意,我希望有人能实现一个更好的Singleton让大家学习。