Qt 單例模式的實現(4種方法)
阿新 • • 發佈:2021-06-22
最簡單的寫法:
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還是有差別的。