最簡單的寫法:
1 static MyClass* MyClass::Instance() 2 { 3 static MyClass inst; 4 return &inst; 5 }
過去很長一段時間一直都這么寫,簡單粗暴有效。但是直接聲明靜態對象會使編譯出的可執行文件增大,也有可能出現其他的一些問題,所以利用了Qt自帶的智能指針QScopedPointer
和線程鎖QMutex
,改成了需要時才動態初始化的模式:
1 static MyClass* MyClass::Instance() 2 { 3 static QMutex mutex; 4 static QScopedPointer<MyClass> inst; 5 if (Q_UNLIKELY(!inst)) { 6 mutex.lock(); 7 if (!inst) { 8 inst.reset(new MyClass); 9 } 10 mutex.unlock(); 11 } 12 return inst.data(); 13 }
既保證了線程安全又防止了內存泄漏,效率也沒降低太多,簡直完美。
可惜每次都要重復這么幾行實在麻煩,於是寫了一個模板類:
1 template <class T>
2 class Singleton 3 { 4 public: 5 static T* Instance() 6 { 7 static QMutex mutex; 8 static QScopedPointer<T> inst; 9 if (Q_UNLIKELY(!inst)) { 10 mutex.lock(); 11 if (!inst) { 12 inst.reset(new T); 13 } 14 mutex.unlock(); 15 } 16 return inst.data(); 17 } 18 };
使用的時候直接這樣——
MyClass* inst = Singleton<MyClass>::Instance();
除了用模板類,還可以利用c++中強大的宏:
1 #define DECLARE_SINGLETON(Class) \
2 Q_DISABLE_COPY(Class) \ 3 public: \ 4 static Class* Instance() \ 5 { \ 6 static QMutex mutex; \ 7 static QScopedPointer<Class> inst; \ 8 if (Q_UNLIKELY(!inst)) { \ 9 mutex.lock(); \ 10 if (!inst) inst.reset(new Class); \ 11 mutex.unlock(); \ 12 } \ 13 return inst.data(); \ 14 }
然后聲明的時候,填加一行這個宏:
1 class MyClass 2 { 3 DECLARE_SINGLETON(MyClass); // 聲明單例模式 4 //...
5 }
好評好評。
當然,為了要保證真的是單例模式,還要把構造函數限制為private,不然以后什么時候忘記了這碼事,在外面又new了一下就不好了。
另外Qt本身自帶了一個宏Q_GLOBAL_STATIC
,也有類似單例模式的效果,QThreadPool::globalInstance()
函數的實現就是利用了這個宏。不過它的主要用處是聲明全局變量,和Singleton還是有差別的。