實現單例模式的**很多。
本文的單例模式實現**是本人一直在工程專案中使用的,現拿出和大家交流分享。
本文實現的單例模式,支援多執行緒,採用雙重校驗檢索的方式,整合析構類,杜絕記憶體洩漏,穩定性好。 使用c++/qt的朋友們可以了解一下。
不再廢話,直接上**。
標頭檔案makelog.h
#include #include class makelog: public qobject
}return m_pinstance;
}private:
makelog(){}
makelog(const makelog&){}
makelog& operator ==(const makelog&){}
static makelog* m_pinstance; //類的指標
static qmutex m_mutex;
public:
class cgarbo //專用來析構m_pinstance指標的類}};
static cgarbo m_garbo;
};
makelog.cpp檔案
makelog* makelog::m_pinstance = null;
makelog::cgarbo m_garbo;
qmutex makelog::m_mutex;
支援多執行緒,無記憶體洩漏的單例模式就實現了。
下面舉例說明具體的使用:
在標頭檔案中加入乙個public函式、乙個public變數。
public:在原始檔中加入函式具體實現,使得readfile()或m_config有實際的意義。void readfile();
qstring m_config;
那麼,在乙個工程內的其他類中,只需做兩個步驟,就可以使用這個readfile()函式和m_config變數了。
步驟1:包含標頭檔案
#include 「makefile.h」步驟2:通過單例類入口呼叫函式或變數
makelog::getinstance()->readfile(); //使用函式單例是一種軟體設計模式,採用單例模式書寫的類可以確保在乙個工程中只有乙個物件例項。再通俗點,就是乙個類寫好了之後,就不需要也無法再把這個類例項化了,因為寫這個類的時候已經確保了有且僅有乙個已經例項化的物件。makelog::getinstance()->m_config; //使用變數
這樣不是很蠢麼?花了這麼多功夫寫了乙個類,你告訴我這個類沒法用來new出物件了?那我怎麼使用這個類?我寫個配合靜態變數的靜態函式,使用起來不是更方便?
當然不蠢,非但不蠢,而且單例模式是所有設計模式中使用最為頻繁的乙個設計模式。沒法new出物件,因為單例模式已經幫你new了乙個物件,而且讓你的工程中只有這個物件了;使用這個物件只需要包含標頭檔案,然後呼叫介面指標函式就可以了;靜態的全域性函式或變數**實現起來方便,但是不具有類的封裝性和靈活性。
首先要清楚類例項化無非就是三種方式:
1)採用建構函式例項化;
2)用拷貝函式實現例項化;
3)賦值操作實現例項化。
所以,只需要把這個類的建構函式、拷貝函式、賦值操作寫成私有的,就無法呼叫這些函式,自然就無法例項化了。
正如上文所示的幾個函式:
private:當然,如果有一些初始化的操作,也可以寫在私有建構函式的雙括號內。makelog(){} //建構函式
makelog(const makelog&){} //拷貝函式
makelog& operator ==(const makelog&){} //賦值操作符重寫
廣泛採用的做法就是在寫乙個public的函式作為介面,這個函式返回單例類唯一例項的指標。
最簡單的寫法如下:
makelog* getinstance()這個寫法看著真不錯,可是這麼寫遇到了乙個小小的悖論。return m_pinstance;
}makelog* m_pinstance; //唯一例項的指標
「我如何去呼叫執行這個getinstance()函式啊,對,我需要乙個例項化物件才能去執行!那我去new個物件,等等,唯一的例項化物件是通過這個函式才能找到的啊!」
有方法解決麼,當然,類的靜態方法不需要例項化物件,用
類名::方法()的形式就可以呼叫執行了,所以把getinstance()函式前加乙個static就好了。
但是靜態方法只能使用靜態成員變數啊,那就把唯一例項的指標m_pinstance也變成static的吧。
ok,這樣有沒有隱患啊?隱患?static型別的instance存在靜態儲存區,每次呼叫時,都指向的同乙個物件。非但沒有隱患,簡直堪稱完美!
現在上面的**就變成這樣:
public:這樣寫完全沒有問題,但是不支援多執行緒的呼叫。因為new makelog()需要時間,所以當兩個執行緒同時判斷m_pinstance ==null,同時執行了m_pinstance = new makelog()這句**,問題就大了。static makelog* getinstance()
return m_pinstance;
}private:
static makelog* m_pinstance; //唯一例項指標
為了解決3.3節產生的bug,廣泛採用的方式是雙重校驗檢索的方法。
就是利用互斥鎖(用來保證鎖內**最多只有乙個執行緒在同時執行)的方式,確保不會出現兩個執行緒同時new出這個單例類的唯一例項的情況發生。
具體**如下:
static makelog* getinstance()至此雙重校驗檢索解決多執行緒問題的單例問題就解決了。當然還可以用原子鎖的方法來解決,但是靈活性不強(也可能是我太外行,靈***來—。—),這裡就不介紹了。}return m_pinstance;
}
解決單例類的記憶體析構主要就是解決static makelog* m_pinstance這個指標的析構問題(畢竟其他的可以不用指標的嘛)。我總結覺得寫乙個專門用來析構的類是最方便有效和無腦的方法了,推薦給大家。
具體就是在單例類中寫乙個類:
public:然後在cpp檔案中宣告一下 makelog::cgarbo m_garbo就可以了。class cgarbo //專用來析構m_pinstance指標的類}};
static cgarbo m_garbo; //宣告乙個靜態的物件
這個類只有析構函式,析構函式的作用就是delete單例唯一物件的指標。
析構類宣告乙個static物件,因為靜態物件系統會在關閉程式時自動析構,就可以執行到析構函式內部的**了。
多執行緒環境下實現單例模式
1 餓漢式 就是在使用類時就將物件建立完畢 例項 public class myobject public static myobject getinstance 測試 public static void main string args 結果 可見hashcode的值一樣的。所有相同物件 2 懶...
多執行緒下的單例模式
單例模式分為兩種 懶漢單例模式和餓漢式單例模式 public class singleton private static singleton single null public static singleton getinstance return single 在單執行緒中,這樣寫,不會存在任...
多執行緒下的單例模式
在多執行緒下的singleton模式是有弊端的,但如何解決呢?辦法是使用lock機制。今天研究的lock機制,並且順便了解了些關於多執行緒的cpu層面的機制。在單個cpu的環境下,在系統的某一時間下cpu只能做一件事情,乙個時間片 slice 這個是cpu執行最小單位。在系統中有多個程序看起來好像是...