2009-04-10 9 views
3

J'écris une bibliothèque de classes d'utilité, dont beaucoup sont des singletons. Je les ai implémentés en tant que tels en utilisant l'héritage:Instances Singleton multiples

template <class T> 
class Singleton { 
    public: 
     T& getInstance() { 
      if(m_instance == 0) { 
       m_instance = new T; 
      } 

      return m_instance; 
     } 
    private: 
     static T* m_instance; 
}; 

class SomeClass : public Singleton<SomeClass> { 
    public: 
     SomeClass() {} 
     virtual ~SomeClass() {} 

     void doSomething() {;} 
}; 

Il s'agit évidemment d'un exemple simple, pas d'une classe réelle. Quoi qu'il en soit, je trouve que l'utilisation de code tel que:

SomeClass::getInstance().doSomething(); 

Permet de créer plus d'une instance de SomeClass. Je pense que cela peut être dû au fait qu'il est utilisé en dehors de mon fichier de bibliothèque (.a) ainsi qu'à l'interne. Par exemple, j'utilise une bibliothèque d'interface utilisateur non écrite par moi-même qui est compilée séparément et à laquelle je fais des ajouts. Certains de ces ajouts utilisent des singletons qui sont également utilisés dans ma bibliothèque.

La compilation séparée provoque-t-elle cela? Autre chose?

La seule façon que j'ai réussi à contourner le problème est de créer un objet global dans mon fichier main.cpp que j'INITIALISER des singletons je aurai besoin. Ensuite, tout le code accède cet objet global commun avec des appels tels que:

GlobalObject::getSomeClass().doSomething() 

Je déteste avoir à ajouter une méthode supplémentaire pour cet objet chaque fois que je crée un autre singleton. De plus la syntaxe semble plus claire et plus familière en utilisant la première méthode d'accès:

SomeClass::getInstance().doSomething(); 

S'il vous plaît laissez-moi savoir si vous avez des pensées, des opinions, etc.

Merci.

+2

Une grande discussion sur la façon de mettre en œuvre un singleton, avec fil de sécurité en C++ se trouve dans cet article: http://www.aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised .pdf –

Répondre

5

Votre problème est que votre modèle va être instancié dans plus d'une unité de compilation car elle est complètement intégrée. Par conséquent, dans chaque unité de compilation qui utilise le modèle, vous allez créer un singleton (par unité de compilation). Ce dont vous avez besoin est de forcer le lien global, de sorte que toutes les unités de compilation référencent la même instanciation de modèle. Le prochain standard C++ supportera ceci via extern template. Ce que vous pouvez faire maintenant est de désactiver l'instanciation automatique dans votre projet et d'instancier manuellement les modèles que vous utilisez explicitement.De cette façon, lorsque vous utilisez le modèle dans une unité de compilation, vous générez une référence inconnue à l'implémentation qui peut ensuite être satisfaite par l'éditeur de liens de l'unité de compilation (une) où vous faites l'instanciation explicite.

+1

Comment forcer le couplage global? – Setheron

1

Plusieurs threads accèdent-ils à getInstance en même temps? Cela pourrait entraîner la création de plusieurs instances. Considérez:

  1. Discussion 1 exécute la « if (m_instance==0) » et trouve vrai
  2. Discussion 2 exécute le « if (m_instance==0) » et trouve vrai
  3. Discussion 1 alloue un nouveau T
  4. Discussion 2 alloue une nouvelle T

Puis l'un d'eux l'autre écrase, et retourne un ou l'autre des cas ou l'autre (en fonction des optimisations du compilateur, etc.)

1

Chaque classe de modèle que vous créez à partir de Singleton va avoir son propre m_instance statique membre ... ceux qui ne sont pas partagés entre les différentes classes parce que quand les modèles sont instanciés, il génère en fait différentes classes pour chaque ensemble de paramètres de modèle. A en juger par la façon dont vous faites votre héritage, cela signifie probablement que vous vous retrouverez avec une instance de Singleton pour chacune des classes qui en dérivent. Peut-être que c'est la cause de votre problème?