一.概念
單例模式:其意圖是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。
[cpp]
class CSingleton
{
//公有的靜態方法,來獲取該實例
public:
static CSingleton* GetInstance()
{
if ( m_pInstance == NULL ) //判斷是否第一次調用
m_pInstance = new CSingleton();
return m_pInstance;
}
//私有構造函數,防止實例化
private:
CSingleton(){};
//私有靜態指針變量,指向類的唯一實例
private:
static CSingleton * m_pInstance; //聲明一個靜態成員
};
CSingleton* CSingleton::m_pInstance = NULL; //定義並初始化靜態數據成員
int main()
{
CSingleton* ps1 = CSingleton::GetInstance();
CSingleton* ps2 = CSingleton::GetInstance();
CSingleton* ps3 = ps1->GetInstance();
CSingleton & ps4 = * CSingleton :: GetInstance();
if (ps1 == ps2)
{
cout<< "ps1 = ps2"<<endl;
}
if (ps1 == ps3)
{
cout<< "ps1 = ps3"<<endl;
}
if (&ps4 == ps1)
{
cout<< "ps1 = ps4"<<endl;
}
return 0;
}
單例模式通過類本身來管理其唯一實例,唯一的實例是類的一個普通對象,但設計這個類時,讓它只能創建一個實例並提供對此實例的全局訪問。
用戶訪問唯一實例的方法只有 GetInstance() 成員函數。如果不通過這個函數,任何創建實例的嘗試都將失敗,因為類的構造函數是私有的。
有一點要注意:一定要加上 CSingleton* CSingleton::m_pInstance = NULL; 這一句,不然的話編譯會出錯,因為這一句才是變量定義。
二.單例類CSingleton 有以下特征 www.2cto.com
它有一個指向唯一實例的靜態指針m_pInstance,並且是私有的;
它有一個公有的函數,可以獲取這個唯一的實例,並且在需要的時候創建該實例;
它的構造函數是私有的,這樣就不能從別處創建該類的實例。
三.存在的問題
1.m_pInstance 指向的空間什麼時候釋放呢?
如果在類的析構行為中有必須的操作,比如關閉文件,釋放外部資源,那麼上面的代碼無法實現這個要求。我們需要一種方法,正常的刪除該實例。
不合理的解決方法:
在程序結束時調用 GetInstance(),並對返回的指針掉用 delete操作。這樣做可以實現功能,但不僅很丑陋,而且容易出錯。因為這樣的附加代碼很容易被忘記,而且也很難保證在delete之後,沒有代碼再調用 GetInstance 函數。也就是說釋放操作由使用者來管理,而不是由類本身來管理,這違背了類的單一職責的原則,這是不合理的。
2. 該實例的析構函數什麼時候執行?
上面的類裡為什麼沒有析構函數,其實即便你加上析構函數也是可以的,但是這個析構函數不會被執行的。因為你的實例是 new 出來的,所以只有 delete 時,才會調用析構函數,但是在哪裡調用 delete 呢!?這又回到了上面的問題。
一種妥善的方法:
[cpp]
class CSingleton
{
public:
static CSingleton* GetInstance()
{
static CSingleton instance; //靜態局部變量
return &instance;
}
private:
CSingleton() {}; //構造函數
};
局部靜態對象實例 instance 是第一次調用 GetInstance() 時被構造,一直保持活動狀態直到應用程序終止,與動態分配對象不同,靜態對象當應用程序終止時被自動銷毀掉,所以就不必再手動銷毀實例了。
當然這裡,可以加上析構函數來處理你想要的操作。
這樣做的要點有以下幾點:
1. 靜態變量在內存中只有一份,從而保證了單例模式中單一實例的要求。
2. 靜態變量在程序終止時會被自動銷毀,從而保證了空間正常釋放。
作者 lwbeyond