有時,我們希望類的實體物件有且僅有一個,比如某個頁面,我們希望它如果出現,永遠只有一個,那么此時你可能就需要用到單例模式了,(PS:本人親身經歷過手寫單例模式的面試,所以以下代碼必須能夠手撕!!!)
單例模式:保證一個類僅有一個實體,并提供一個訪問它的全域訪問點,首先,怎么讓類只有一個實體呢?肯定是建構式需要做點“手腳”了,如果建構式一如既往的是public屬性,那還是可以任意構造物件,則不滿足要求了,所以大神們想出來將建構式私有化的方法,即把建構式設定成私有屬性,并對外提供一個訪問的介面,
單例模式的實作有兩種方式:懶漢模式和餓漢模式,懶漢模式:顧名思義,很“懶”,只有用到了才實體化物件并回傳(呼叫了對外的介面才會實體化物件),餓漢模式:不管調不呼叫對外介面,都已經實體化物件了,下面先實作基本的懶漢模式,代碼如下:
#include<iostream>
using namespace std;
/*單例模式:建構式私有化,對外提供一個介面*/
//執行緒不安全的懶漢模式
class singleClass {
public:
static singleClass* instance;//靜態成員變數,類內宣告,類外初始化
static singleClass* getinstance()//對外的介面(方法),靜態成員函式呼叫靜態成員變數
{
if (instance == nullptr)
{
instance = new singleClass();
}
return instance;
};
private:
singleClass() {};//建構式屬性設定為私有
};
singleClass* singleClass::instance=nullptr;//初始化靜態變數
int main()
{
//懶漢模式
singleClass* singlep1=singleClass::getinstance();//通過類域獲取介面
singleClass* singlep2 = singleClass::getinstance();
cout << singlep1 << endl;
cout << singlep2 << endl;
system("pause");
return 0;
}
由于沒有了物件,所以將instance設定為static屬性,讓其能通過類名來訪問獲取,但是在多執行緒環境下,這種實作方式是不安全的,原因在于在判斷instance是否為空時,可能存在多個執行緒同時進入if中,此時可能會實體化多個物件,于是,我了解決這個問題,出現了二重鎖的懶漢模式,實作代碼如下:
#include<iostream>
#include<mutex>
using namespace std;
/*單例模式:建構式私有化,對外提供一個介面*/
//執行緒安全的單例模式
class lhsingleClass {
public:
static lhsingleClass* instance;
static mutex i_mutex;//鎖
static lhsingleClass* getinstance()
{//雙重鎖模式
if (instance == nullptr)
{//先判斷是否為空,如果為空則進入,不為空說明已經存在實體,直接回傳
//進入后加鎖
i_mutex.lock();
if (instance == nullptr)
{//再判斷一次,確保不會因為加鎖期間多個執行緒同時進入
instance = new lhsingleClass();
}
i_mutex.unlock();//解鎖
}
return instance;
}
private:
lhsingleClass(){}
};
lhsingleClass* lhsingleClass::instance=nullptr;
mutex lhsingleClass::i_mutex;//類外初始化
int main()
{
lhsingleClass* lhsinglep5 = lhsingleClass::getinstance();
lhsingleClass* lhsinglep6 = lhsingleClass::getinstance();
cout << lhsinglep5 << endl;
cout << lhsinglep6 << endl;
system("pause");
return 0;
}
以上就是單例模式的懶漢實作方式,下面介紹餓漢實作方式:
#include<iostream>
using namespace std;
/*單例模式:建構式私有化,對外提供一個介面*/
//餓漢模式:不管用不用得到,都構造出來,本身就是執行緒安全的
class ehsingleClass {
public:
static ehsingleClass* instance;//靜態成員變數必須類外初始化,只有一個
static ehsingleClass* getinstance()
{
return instance;
}
private:
ehsingleClass() {}
};
ehsingleClass* ehsingleClass::instance = new ehsingleClass();
//類外定義,main開始執行前,該物件就存在了
int main()
{
//餓漢模式
ehsingleClass* ehsinglep3 = ehsingleClass::getinstance();
ehsingleClass* ehsinglep4 = ehsingleClass::getinstance();
//ehsingleClass* ehsinglep5 = ehsingleClass::get();//非靜態成員方法必須通過物件呼叫,不能通過類域訪問
cout << ehsinglep3 << endl;
cout << ehsinglep4 << endl;
system("pause");
return 0;
}
餓漢式即一種靜態初始化的方式,它是類一加載就實體化物件,所以要提前占用系統資源,而懶漢式又面臨著多執行緒不安全的問題,需要加二重鎖才能保證安全,因此具體使用哪種模式,需要根據實際需求和場景來定,
以上就是單例模式的實作方式啦,本人也是剛學習總結,如有錯誤,歡迎指正交流,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/231098.html
標籤:其他
上一篇:muduo原始碼分析3——TSD
