定義:單件模式確保一個類只有一個實例,並提供一個全局訪問點
實現一:
#include <iostream>
using namespace std;
class CSingleton
{
public:
static CSingleton* getInstance();
static void cleanInstance();
int getValue();
void setValue(int iValue);
private:
int m_iValue;
static CSingleton* m_pSingleton;
CSingleton();
~CSingleton();
};
CSingleton* CSingleton::m_pSingleton = NULL;
CSingleton::CSingleton()
{
cout << "Constructor" << endl;
}
CSingleton::~CSingleton()
{
cout << "Destructor" << endl;
}
CSingleton* CSingleton::getInstance()
{
if (NULL == m_pSingleton)
{
m_pSingleton = new CSingleton();
}
return m_pSingleton;
}
void CSingleton::cleanInstance()
{
delete m_pSingleton;
}
int CSingleton::getValue()
{
return m_iValue;
}
void CSingleton::setValue(int iValue)
{
m_iValue = iValue;
}
int main()
{
CSingleton* pSingleton1 = CSingleton::getInstance();
CSingleton* pSingleton2 = CSingleton::getInstance();
pSingleton1->setValue(123);
if (pSingleton1->getValue() == pSingleton2->getValue())
{
cout << "Two objects is the same instance" << endl;
}
else
{
cout << "Two objects isn't the same instance" << endl;
}
CSingleton::cleanInstance();
return 0;
}
相信大多數的同仁都喜歡使用上邊這種單件模式的實現方法,如果在單線程的情況下,是沒有問題的,但如果是多線程,那么就極有可能會返回兩個不同的對象,在調用
CSingleton::getInstance的時候,兩個線程如果都同時運行完if判斷,而又還沒有調用到構造函數的話,想象下后果吧。那該怎么辦呢?看下邊這個實現吧。
實現二:
#include <iostream>
using namespace std;
class CSingleton
{
public:
static CSingleton* getInstance();
static void cleanInstance();
int getValue();
void setValue(int iValue);
private:
int m_iValue;
static CSingleton* m_pSingleton;
CSingleton();
~CSingleton();
};
// 在進程運行開始就實例化該單件,又稱“急切”創建實例
CSingleton* CSingleton::m_pSingleton = new CSingleton();
CSingleton::CSingleton()
{
cout << "Constructor" << endl;
}
CSingleton::~CSingleton()
{
cout << "Destructor" << endl;
}
CSingleton* CSingleton::getInstance()
{
return m_pSingleton;
}
void CSingleton::cleanInstance()
{
delete m_pSingleton;
}
int CSingleton::getValue()
{
return m_iValue;
}
void CSingleton::setValue(int iValue)
{
m_iValue = iValue;
}
int main()
{
CSingleton* pSingleton1 = CSingleton::getInstance();
CSingleton* pSingleton2 = CSingleton::getInstance();
pSingleton1->setValue(123);
if (pSingleton1->getValue() == pSingleton2->getValue())
{
cout << "Two objects is the same instance" << endl;
}
else
{
cout << "Two objects isn't the same instance" << endl;
}
CSingleton::cleanInstance();
return 0;
}
哈哈,看清楚了嗎?就是在進程運行的時候就對這個單件進行實例化,可是這樣似乎又不能達到延遲實例化的目的啦。如果我們的對象對資源占用非常大,而我們的進行在整個過程中其實並沒有用到這個單件,那豈不是白白浪費資源了嘛。還有更好的辦法。
實現三:
#include <iostream>
using namespace std;
class CSingleton
{
public:
static CSingleton* getInstance();
int getValue();
void setValue(int iValue);
private:
int m_iValue;
CSingleton();
~CSingleton();
};
CSingleton::CSingleton()
{
cout << "Constructor" << endl;
}
CSingleton::~CSingleton()
{
cout << "Destructor" << endl;
}
CSingleton* CSingleton::getInstance()
{
static CSingleton single;
return &single;
}
int CSingleton::getValue()
{
return m_iValue;
}
void CSingleton::setValue(int iValue)
{
m_iValue = iValue;
}
int main()
{
cout << "Process begin" << endl;
CSingleton* pSingleton1 = CSingleton::getInstance();
CSingleton* pSingleton2 = CSingleton::getInstance();
pSingleton1->setValue(123);
if (pSingleton1->getValue() == pSingleton2->getValue())
{
cout << "Two objects is the same instance" << endl;
}
else
{
cout << "Two objects isn't the same instance" << endl;
}
return 0;
}
看下運行結果吧:
Process begin
Constructor
Two objects is the same instance
Destructor
是不是跟預想的一樣呢?把單件聲明為成員函數中的靜態成員,這樣既可以達到延遲實例化的目的,又能達到線程安全的目的,而且看結果的最后,是不是在程序退出的時候,還自動的調用了析構函數呢?這樣我們就可以把資源的釋放放到析構函數里邊,等到程序退出的時候,進程會自動釋放這些靜態成員的。
參考圖書:《Head First 設計模式》