單例模式的應用場景:ios
一、windows的任務管理器,沒法打開兩個任務管理器。windows
二、windows的回收站。安全
三、網站的計數器,通常也是採用單例模式實現,不然難以同步多線程
四、 應用程序的日誌應用,通常都何用單例模式實現,這通常是因爲共享的日誌文件一直處於打開狀態,由於只能有一個實例去操做,不然內容很差追加。函數
1、單例模式類CSingleton有如下幾個特性:性能
一、它有一個指向惟一實例的靜態指針m_pInstance,而且是私有的。網站
二、它有一個公有的函數,能夠獲取建立的這個惟一的實例,而且在須要的時候建立該實例。spa
三、它的構造函數是私有的,這樣就不能從別處建立該類的實例。線程
代碼以下:指針
class CSingleton { private: CSingleton() //構造函數是私有的 { } static CSingleton *m_pInstance; public: static CSingleton * GetInstance() { if(m_pInstance == NULL) //判斷是否第一次調用 m_pInstance = new CSingleton(); return m_pInstance; } };
2、m_pInstance指向的空間何時釋放?該實例的析構函數何時執行?
一、須要知道一點:程序在結束的時候,系統會自動析構全部的全局變量。事實上,系統也會析構全部的類的靜態成員變量,就像這些靜態成員也是全局變量同樣。
二、如上所述,咱們能夠利用這個特徵,咱們能夠在單例類中定義一個這樣的靜態成員變量,而它的惟一工做就是在析構函數中刪除單例類的實例。例以下面代碼中的CGarbo類。(Garbo意爲垃圾工人)
class CSingleton { private: CSingleton() { } static CSingleton *m_pInstance; class CGarbo //它的惟一工做就是在析構函數中刪除CSingleton的實例 { public: ~CGarbo() { if(CSingleton::m_pInstance) delete CSingleton::m_pInstance; } }; static CGarbo Garbo; //定義一個靜態成員變量,程序結束時,系統會自動調用它的析構函數 public: static CSingleton * GetInstance() { if(m_pInstance == NULL) //判斷是否第一次調用 m_pInstance = new CSingleton(); return m_pInstance; } };
CGaibo類是Csingleton類私有內嵌類,防止改類在別的地方被濫用。
程序結束的時候,系統會調用CSingleton類中的CGarbo類的析構函數,該析構函數會刪除單例的惟一的實例。
使用這種方式釋放單例對象有如下特徵:
完整的代碼以下:
#include <iostream> using namespace std; class CSingleton { public: static CSingleton *GetInstance(); private: CSingleton() { cout << "CSingleton ctor" << endl; } ~CSingleton() { cout << "CSingleton dtor" << endl; } static CSingleton *m_pInstance; class Garbo { public: ~Garbo() { if (CSingleton::m_pInstance) { cout << "Garbo dtor" << endl; delete CSingleton::m_pInstance; } } }; static Garbo garbo; }; CSingleton::Garbo CSingleton::garbo; // 必定要初始化,否則程序結束時不會析構garbo CSingleton *CSingleton::m_pInstance = NULL; CSingleton *CSingleton::GetInstance() { if (m_pInstance == NULL) m_pInstance = new CSingleton; return m_pInstance; } int main() { CSingleton *p1 = CSingleton::GetInstance(); CSingleton *p2 = CSingleton::GetInstance(); if (p1 == p2) cout << "p1 == p2" << endl; return 0; }
補:
一、餓漢模式:
即第一次調用該類實例的時候才產生一個新的該類實例,並在之後僅返回此實例。
須要用鎖,來保證其線程安全性:緣由:多個線程可能進入判斷是否已經存在實例的if語句,從而non thread safety.
使用double-check來保證thread safety.可是若是處理大量數據時,該鎖才成爲嚴重的性能瓶頸。
二、懶漢模式:
即不管是否調用該類的實例,在程序開始時就會產生一個該類的實例,並在之後僅返回此實例。
由靜態初始化實例保證其線程安全性,WHY?由於靜態實例初始化在程序開始時進入主函數以前就由主線程以單線程方式完成了初始化,沒必要擔憂多線程問題。
故在性能需求較高時,應使用這種模式,避免頻繁的鎖爭奪。