Qt-单例模式实例
單例模式
單利模式作為一種常用的軟件設(shè)計(jì)模式,主要是用來(lái)保證系統(tǒng)中只有一個(gè)實(shí)例,例如一般一個(gè)程序中只有一個(gè)日志輸出實(shí)例,一個(gè)系統(tǒng)中只有一個(gè)數(shù)據(jù)庫(kù)連接實(shí)例,這時(shí)候用單例模式非常合適。
簡(jiǎn)單的單例模式
1 class QSingleton2 {3 public:4 static QSingleton* instance()5 {6 if (m_pInstance == NULL)7 {8 m_pInstance = new QSingleton();9 } 10 return m_pInstance; 11 } 12 13 static void Release() 14 { 15 if (m_pInstance != NULL) 16 { 17 delete m_pInstance; 18 m_pInstance = NULL; 19 } 20 } 21 private: 22 QSingleton(){} 23 QSingleton(const QSingleton&){} 24 QSingleton& operator==(const QSingleton&){} 25 private: 26 static QSingleton* m_pInstance; 27 }; 28 // 靜態(tài)成員變量需要在類體的外面進(jìn)行初始化 29 QSingleton* QSingleton::m_pInstance = NULL;上面的實(shí)現(xiàn)一種最簡(jiǎn)單的單利模式,是一種懶漢模式,所謂的懶漢模式就是在程序需要時(shí)才進(jìn)行成員變量的創(chuàng)建也就是“延時(shí)加載”,與之相對(duì)的就是餓漢模式,惡漢模式就是在程序啟動(dòng)時(shí)就需要?jiǎng)?chuàng)建變量。懶漢模式是時(shí)間換空間,惡漢模式是空間換時(shí)間,看如下惡漢模式的一個(gè)簡(jiǎn)單實(shí)現(xiàn):
1 class QSingleton2 {3 public:4 static QSingleton* instance()5 {6 return m_pInstance;7 }8 9 static void Release() 10 { 11 if (m_pInstance != NULL) 12 { 13 delete m_pInstance; 14 m_pInstance = NULL; 15 } 16 } 17 QSingleton(){} 18 19 private: 20 QSingleton(const QSingleton&){} 21 QSingleton& operator==(const QSingleton&){} 22 private: 23 static QSingleton* m_pInstance; 24 }; 25 26 // 直接初始化靜態(tài)成員變量 27 QSingleton* QSingleton::m_pInstance = new QSingleton;因?yàn)槌绦騿?dòng)時(shí),就需要?jiǎng)?chuàng)建對(duì)象,所以單例類的默認(rèn)構(gòu)造函數(shù)就需要時(shí)public的,此時(shí)用戶就能夠創(chuàng)建單例類的對(duì)象,從而就不能保證單例模式的初衷:一個(gè)程序只有一個(gè)實(shí)例類,另外當(dāng)我們的單例類的默認(rèn)構(gòu)造函數(shù)需要參數(shù)時(shí),并且改參數(shù)需要在程序執(zhí)行過(guò)程中才能夠構(gòu)造,此時(shí)就不能用餓漢模式的單例模式。因此下面著重對(duì)懶漢模式的單例模式實(shí)現(xiàn)做討論。上面的簡(jiǎn)單的懶漢模式的單例類實(shí)現(xiàn)有如下缺點(diǎn):
每次都得判斷m_pInstance是否為空,增加了程序開(kāi)銷,而餓漢模式?jīng)]有此問(wèn)題。
需要手動(dòng)調(diào)用Release函數(shù)釋放靜態(tài)成員變量分配內(nèi)存,上面的餓漢模式也有此問(wèn)題。針對(duì)此問(wèn)題我們可以通過(guò)智能指針來(lái)避免。
不是線程安全的,要想在多線程環(huán)境下安全使用,就需要在程序一開(kāi)始處,其他線程還未創(chuàng)建時(shí),調(diào)用一次instance函數(shù),但這樣就拋棄了懶漢模式延遲加載的優(yōu)點(diǎn)。餓漢模式因?yàn)樵诔绦蛞婚_(kāi)始就創(chuàng)建了對(duì)象,因此是線程安全的。
線程安全的單例模式
通過(guò)智能指針來(lái)管理成員變量,保證了在程序退出時(shí),自動(dòng)釋放內(nèi)存,通過(guò)加鎖保證了m_pInstance創(chuàng)建的唯一性,但是因?yàn)槌绦蛎看握{(diào)用instance就需要先加鎖,大大增加了程序開(kāi)銷,看如下改進(jìn)實(shí)現(xiàn):
1 class QSingleton2 {3 public:4 static QSharedPointer<QSingleton>& instance()5 {6 7 if (m_pInstance.isNull())8 {9 QMutexLocker mutexLocker(&m_Mutex); 10 if (m_pInstance.isNull()) 11 m_pInstance = QSharedPointer<QSingleton>(new QSingleton()); 12 } 13 return m_pInstance; 14 } 15 private: 16 QSingleton(){} 17 QSingleton(const QSingleton&){} 18 QSingleton& operator==(const QSingleton&){} 19 private: 20 static QMutex m_Mutex; 21 static QSharedPointer<QSingleton> m_pInstance; 22 }; 23 24 QMutex QSingleton::m_Mutex; 25 QSharedPointer<QSingleton> QSingleton::m_pInstance;上面的實(shí)現(xiàn)通過(guò)兩次檢查成員變量是否為空(double-check),避免了每次調(diào)用instance函數(shù)就鎖定的效率問(wèn)題。
Meyers提出的一種單例模式的實(shí)現(xiàn)
1 class QSingleton2 {3 public:4 static QSingleton& instance()5 {6 static QSingleton qinstance;7 return qinstance;8 }9 private: 10 QSingleton(){} 11 QSingleton(const QSingleton&){} 12 QSingleton& operator==(const QSingleton&){} 13 };在上述單例模式的實(shí)現(xiàn)中,在instance函數(shù)中聲明static的局部變量,因?yàn)殪o態(tài)變量在程序中只會(huì)分配一次內(nèi)存,保證了實(shí)例的唯一性,并且作為局部變量只有在程序第一次調(diào)用的時(shí)候才會(huì)初始化,也實(shí)現(xiàn)了延遲加載,而且因?yàn)椴皇侵羔樧兞?#xff0c;在程序結(jié)束時(shí)會(huì)自動(dòng)回收內(nèi)存,幾乎就是完美的實(shí)現(xiàn)。雖然是只分配一次內(nèi)存,但就能夠確保線程安全嗎?答案是否定的,因?yàn)閏++的構(gòu)造函數(shù)本身就不是線程安全的,當(dāng)我們?cè)跇?gòu)造函數(shù)內(nèi)部初始化成員變量或者全局變量時(shí),時(shí)間片就有可能被切走,我們?cè)谑褂脮r(shí),這一點(diǎn)尤為重要。
總結(jié)
- 上一篇: Halcon 3D点云和深度图的相互转化
- 下一篇: 2015Astar百度之星初赛 1005