2012-06-29 191 views
2

有人告訴我,我的單身模板可能不是真正的單身人士,因爲有辦法用它創建多個對象。當我問及如何解決這個問題時,我被忽略了。這就是爲什麼我來這裏要問的是,我的單身模板類真的是單身?我的單身人士模板真的是單身人士嗎?

#ifndef SINGLETON_H_ 
#define SINGLETON_H_ 

template <class T> 
class Singleton 
{ 
private: 
static T* instance; 

protected: 
    Singleton<T>() 
    { 
    } 

public: 
    static T* getInstancePtr() 
    { 
     if (instance == 0) 
      instance = new T(); 

     return instance; 
    } 
}; 

template <class T> T* Singleton<T>::instance = 0; 

#endif 

然後,這是由類繼承的,我希望成爲像這樣一個單: -

class Console : public Singleton<Console> 
{ 
}; 
+8

你試過編譯'控制檯C1,C2;'? –

+0

我剛剛找到了一種方法來規避單個實例。如果我用控制檯c1初始化控制檯;我有一個c1的控制檯實例,以及Singleton類實例指針中的Console實例的第二個實例。 – ctor

回答

2

使用局部靜態變量實現單件模式:

template <class T> 
class Singleton 
{ 
    static T* getInstancePtr() 
    { 
     static T instance; // <-- HERE 

     return &instance; 
    } 
}; 
從更少的代碼

除此之外,它也有保證線程安全的。它將在第一次撥打Singleton<X>::getInstancePtr()時構建,並且連續的呼叫將獲得一個實例。

或者,如果你想每一個線程一個實例您可以使用thread_local代替:

template <class T> 
class Singleton 
{ 
    static T* getInstancePtr() 
    { 
     thread_local T instance; // <-- HERE 

     return &instance; 
    } 
}; 
3

一個簡單的理由,爲什麼你不能保證它是一個單身是因爲線程安全。

如果兩個或多個線程同時調用getInstancePtr,則根據線程交換,最終可能會有兩個或更多實例。

+0

OP的問題與多線程無關,Singleton也不是多線程獨有的。 – phonetagger

4

您已將默認構造函數protected。派生類可以訪問它,因此這將編譯:

Console c1, c2; 
+2

請不要將其他人的評論重新發布爲答案。 –

+2

@Nikolai - 爲什麼呢? –

+0

@Charles Q已編輯,現在有定義。 @Nikolai你有沒有寫過'std :: string str;'?我也是。 – jrok

0

要在多線程環境中工作,你需要不同的解決方案。您必須使用特定的語言功能來確保在存在多個線程的情況下只創建對象的一個​​實例。更常見的解決方案之一是使用Double-Check Locking成語來讓單獨的線程同時創建單例的新實例。

+0

OP的問題與多線程無關,Singleton也不是多線程所獨有的。 – phonetagger

0

好吧,除了多線程的問題之外,還有一種情況是我可以創建兩個實例。通過初始化以下

class Console : public Singleton<Console> 
{ 
}; 

類控制檯,像這樣

Console c1; 

我是控制檯的兩個實例,一個在Singleton類中保存的實例的指針和一個C1對象本身結束了。我通過將Singleton類更改爲以下來解決此問題。

#ifndef SINGLETON_H_ 
#define SINGLETON_H_ 

template <class T> 
class Singleton 
{ 
private: 
    static T* instance; 

protected: 
    Singleton<T>() 
    { 
     if (instance == 0) 
      instance = static_cast<T*>(this); 
    } 

public: 
    static T* getInstancePtr() 
    { 
     return instance; 
    } 
}; 

template <class T> T* Singleton<T>::instance = 0; 

#endif 

但除了多線程問題,我現在更確定我的Singleton類將不太可能導致多個實例。

+0

這並沒有解決它。 'instance'將指向構造的第一個實例,但仍然可以根據需要默認構造派生類的許多實例(除非派生類的構造函數也是私有的)。 http://ideone.com/Y0zPo – jrok

+1

我已經修復它並將Singleton作爲朋友添加到繼承它的類中。謝謝 :) – ctor

1

我使用了與您相同的單例模板,但將其留給用戶來創建私有構造函數和析構函數。 用戶將不得不友好單身人士班,但它接近我想要的,它可以作爲一個單身人士使用。 它不是線程安全的(但),但它'解決'多實例問題。