題目:
設計一個類,我們只能生成該類的一個實例。
解答:
單例模式的類有以下幾個特徵:
1.構造函數是private。
2.有一個唯一實例的靜態指針,且是private。
3.有一個public接口函數,獲得該唯一實例的指針。
解法一:
按照上面的特徵實現的單例類如下:
-
class Singleton{
-
public:
-
static Singleton* getInstance();
-
private:
-
Singleton();
-
static Singleton* m_pInstance;
-
};
-
-
Singleton* m_pInstance = NULL;
-
Singleton* getInstance()
-
{
-
if (m_pInstance == NULL) m_pInstance = new Singleton();
-
return m_pInstance;
-
}
但是上述類存在static變量,如果在單線程模式下OK,但是在多線程模式下,就可能產生與初始化有關的“競速形勢”(條款04)。
條款04中提供了一種方法解決“競速形勢”,就是在程序的單線程啓動階段,手動調用所有reference-returning函數。這顯然有點麻煩。
以後補充多線程安全的單例模式。
解法二:利用互斥鎖
可以用一個互斥鎖將該方法鎖住,每次只能有一個線程訪問該方法,缺點是加鎖是耗時操作,效率較低。
-
class Singleton{
-
public:
-
static Singleton* getInstance();
-
private:
-
Singleton();
-
static Singleton* m_pInstance;
-
};
-
-
Singleton* m_pInstance = NULL;
-
Singleton* getInstance()
-
{
-
lock(mutex){
-
if (m_pInstance == NULL) m_pInstance = new Singleton();
-
return m_pInstance;
-
}
-
}
效率比這個高的是加鎖前判斷實例是否已經存在。解法三(強烈推薦):利用靜態構造函數(設計模式中的方法)
其實一旦設置好m_pInstance就不需要同步了,因此提前創建實例,而不用延遲實例化的方法。
-
class Singleton{
-
private:
-
Singleton();
-
static Singleton* m_pInstance = new Singleton();
-
public:
-
static Singleton* getInstance(){ return m_pInstance; }
-
};
可惜,上面會提示錯誤:a member with a in-class initializer must be const改成下面這樣可以:
-
class Singleton{
-
private:
-
Singleton();
-
static const Singleton* m_pInstance ;
-
public:
-
static const Singleton* getInstance(){ return m_pInstance; }
-
};
-
-
const Singleton* Singleton::m_pInstance = new Singleton();