2012-06-29 1 views
2

On m'a dit que mon modèle singleton ne peut pas vraiment être un singleton, car il y a des façons de créer plus d'un objet avec lui. Quand j'ai demandé comment le réparer, j'ai été ignoré. C'est pourquoi je viens ici pour demander est ma classe modèle singleton vraiment un singleton?Est-ce que mon modèle singleton est vraiment un singleton?

#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 

Il est ensuite héritée par une classe que je veux être un singleton comme ceci: -

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

Avez-vous essayé de compiler 'Console c1, c2,'? –

+0

Je viens de trouver un moyen de contourner l'instance unique.Si j'initialise la console avec la console c1; J'ai une instance de Console pour c1 et une 2ème instance de Console dans le pointeur d'instance dans la classe Singleton. – ctor

Répondre

2

Utilisez une variable statique locale pour mettre en œuvre le modèle singleton:

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

     return &instance; 
    } 
}; 

A part beaucoup moins de code, il est également garanti thread-safe. Il sera construit sur le premier appel à Singleton<X>::getInstancePtr() et les appels successifs obtiendront une instance.

Alternativement, si vous voulez un exemple par thread, vous pouvez utiliser à la place thread_local:

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

     return &instance; 
    } 
}; 
3

Une simple raison pour laquelle vous ne pouvez pas garantir que c'est un singleton est dû à Réentrance .

Si deux threads ou plus appellent getInstancePtr en même temps, vous pouvez vous retrouver avec deux instances ou plus en fonction de l'échange de threads.

+0

La question de l'OP n'a rien à voir avec le multithreading, et les singletons ne sont pas uniques au multithread non plus. – phonetagger

4

Vous avez créé le constructeur par défaut protected. La classe dérivée peut accéder, donc ce compilera:

Console c1, c2; 
+2

S'il vous plaît ne pas re-poster les commentaires des autres personnes comme réponses. –

+2

@Nikolai - pourquoi ça? –

+0

@Charles Le Q a été modifié, il y a une définition maintenant. @Nikolai Avez-vous déjà écrit 'std :: string str;'? Je l'ai fait aussi. – jrok

0

Pour travailler dans un environnement multithread, vous avez besoin d'une autre solution. Vous devez utiliser des fonctionnalités de langage spécifiques pour vous assurer qu'une seule instance de l'objet est créée en présence de plusieurs threads. L'une des solutions les plus courantes consiste à utiliser l'idiome Double-Check Locking pour empêcher les threads distincts de créer de nouvelles instances du singleton en même temps.

+0

La question de l'OP n'a rien à voir avec le multithreading, et les singletons ne sont pas uniques au multithread non plus. – phonetagger

0

Ok donc, outre les problèmes de multi-threading, il y avait un cas où je pouvais créer deux instances. En initialisant la classe Console ci-dessous

class Console : public Singleton<Console> 
{ 
}; 

comme si

Console c1; 

J'étais finir avec deux instances de la console, l'un dans le pointeur d'instance tenue dans la classe Singleton et un dans l'objet c1 lui-même. J'ai résolu ceci en changeant la classe de Singleton à la suivante.

#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 

Cependant, d'autres que les questions multi-threading Je suis maintenant plus sûr que ma classe Singleton sera moins susceptible d'entraîner plusieurs instances.

+0

Cela ne le résout pas. 'instance' pointera vers la première instance construite, mais vous pouvez toujours construire par défaut autant d'instances de la classe dérivée que vous le souhaitez (à moins que vous ne rendiez les constructeurs de classes dérivées aussi privés). http://ideone.com/Y0zPo – jrok

+1

Je l'ai corrigé et ajouté Singleton en tant qu'ami aux classes qui l'ont hérité. Merci :) – ctor

1

J'ai utilisé le même modèle de singleton que vous, mais je laisse à l'utilisateur le soin de créer des constructeurs et des destructeurs privés. l'utilisateur devra se lier d'amitié avec la classe singleton mais il est proche de ce que je veux et il peut être utilisé comme singleton. Ce n'est pas (encore) threadsafe, mais il résout le problème d'instance multiple.