[c++] class singleton

class singleton [c++] - C++ - Programmation

Marsh Posté le 02-08-2004 à 18:00:30    

Je decouvre qu'il existait une classe de base pour faire un singleton, je croyais que c'etait pas possible... à cause en particulier du static instance.
 

Code :
  1. template< typename X >
  2. struct singleton
  3. {
  4. inline static X* instancier();
  5. protected:
  6. singleton() {};
  7. virtual ~singleton() {};
  8. singleton( const singleton& ) {};
  9. singleton& operator=( const singleton& ) {};
  10. private:
  11. static X* instance;
  12. };
  13. template< typename X >
  14. X* singleton<X>::instance( 0 );
  15. template< typename X >
  16. X* singleton<X>::instancier()
  17. {
  18. if( instance == 0 )
  19. instance = new X;
  20. return instance;
  21. }
  22. // template de classe derivée
  23. class X : public singleton<X> ...


 
La classe est semble t il incomplete, mais ca donne une idée.


Message édité par xterminhate le 04-08-2004 à 12:16:23

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-08-2004 à 18:00:30   

Reply

Marsh Posté le 03-08-2004 à 09:14:30    

Bien :jap:
 
Aucune lib n'en fournit une ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 03-08-2004 à 10:27:56    

si. merde j'ai oublié de répondre hier soir. utilise un truc genre smart pointer pour éviter tout fuite.

Reply

Marsh Posté le 03-08-2004 à 11:04:12    

boost::scoped_ptr serait approprié ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 03-08-2004 à 11:13:30    

non. un simple std::auto_ptr suffit je pense

Reply

Marsh Posté le 03-08-2004 à 19:06:23    

Ca permettrait de ne pas appeler explicitement un methode de destruction, c'est bien ca ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 03-08-2004 à 19:25:09    

oui. fais le test, tu verras

Reply

Marsh Posté le 04-08-2004 à 12:19:50    

En ré-ecrivant le membre "static auto_ptr<X> instance", est ce vraiment compatible de la foncion membre instancier() ( copie de autoptr à la ligne return instance ? ).


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 04-08-2004 à 12:21:35    

heink ?

Reply

Marsh Posté le 04-08-2004 à 12:40:55    

Au temps pour moi, j'ai forcé sur le rouge à midi!  :pt1cable:  
 

Code :
  1. template< typename X >
  2. struct singleton
  3. {
  4. inline static X* instancier();
  5. protected:
  6. singleton() {};
  7. virtual ~singleton() {};
  8. singleton( const singleton& ) {};
  9. singleton& operator=( const singleton& ) {};
  10. private:
  11. static std::auto_ptr<X> instance;
  12. };
  13. template< typename X >
  14. std::auto_ptr<X> singleton<X>::instance( 0 );
  15. template< typename X >
  16. X* singleton<X>::instancier()
  17. {
  18. if( instance.get() == 0 )
  19. instance.reset( new X );
  20. return instance.get();
  21. }


 
Je suis pas trop sur, je maitrise pas l'auto_ptr.


Message édité par xterminhate le 04-08-2004 à 12:41:08

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 04-08-2004 à 12:40:55   

Reply

Marsh Posté le 04-08-2004 à 14:14:33    

vous avez vraiment le chic pour faire compliquer. ni membre statique ni rien, juste un static dans une fonction et directement initialisé.|

Reply

Marsh Posté le 04-08-2004 à 14:41:54    

Code :
  1. #include <memory>
  2. template< typename X >
  3. struct singleton
  4. {
  5.     inline static X& get()
  6. {
  7.  static std::auto_ptr<X> obj;
  8.  if(!obj.get())
  9.   obj.reset(new X);
  10.  return *obj;
  11. }
  12. };
  13. class X : public singleton<X> ...


 
comme ca alors ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 04-08-2004 à 14:54:31    

pourquoi tu veux pas initialiser ton obj ?

Reply

Marsh Posté le 04-08-2004 à 14:58:24    

non comme ca:
 

Code :
  1. template<typename X> class singleton
  2. {
  3. public:
  4.     static X& get()
  5. {
  6.  static X obj;
  7.  return obj;
  8. }
  9. protected:
  10. singleton() {}
  11. };
  12. class X : public singleton<X>
  13. {
  14. protected:
  15. X() {}
  16. };


 
Tu n'as pas besoin de mettre inline a partir du moment ou la methode est implemetee dans la definition de la classe...


Message édité par mynab le 04-08-2004 à 15:00:02
Reply

Marsh Posté le 04-08-2004 à 15:55:26    

note que je ne sais pas dans quelle mesure c'est vrai, mais le fait d'utiliser une instance statique et no pas un pointeur peut poser de sérieux problèmes:
 
1. tu dois avoir une initialisation indépendante de toutes les autres données de ton système puisque tu ne peux pas présupposer de l'ordre de l'initialisation des varaiables statiques et des varaiables globales
 
2. dans le cas où ce code se retrouve dans une bibliothèque dynamique contenant du code C++, les objets statiques sont instanciés sans que le constructeur soit appelé si le programme appelant a été écrit/compilé en C (pb bien connu par ceux qui écrivent des extensions pour Python en C++). Dans ce cas, il vaut mieux passer par un pointeur initialisé à 0 et créer l'instance dynamiquement au premier appel.

Reply

Marsh Posté le 04-08-2004 à 16:03:54    

bin dans un cas l'objet sera créé au lancement du programme, dans l'autre cas à la 1ere demande de l'objet ... je ne sais pas si c'est important ...


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 04-08-2004 à 16:07:06    

dans tous les cas, j'aime pas trop les singleton en C/C++, je préfère les implémentations dans les langages qui permettent les weakref, genre python, je me sens plus tranquille quand on me réclame un truc, je file une weakref et voilà

Reply

Marsh Posté le 04-08-2004 à 16:20:27    

d'ailleurs j'aime bien aussi le borg-shared-state pattern

Reply

Marsh Posté le 04-08-2004 à 16:24:10    

google(borg-shared-state pattern) => 'did not match any documents'. c'est quoi donc ce pattern?

Reply

Marsh Posté le 04-08-2004 à 16:26:54    

BlackGoddess a écrit :

bin dans un cas l'objet sera créé au lancement du programme, dans l'autre cas à la 1ere demande de l'objet ... je ne sais pas si c'est important ...


ça peut l'être si la construction de cet objet nécessite la collaboration d'autres objets, ou dans le cas (2) que j'ai indiqué; par contre pour l'utilisateur de cette méthode peut importe.
Mais quand on choisit une implémentation plutôt qu'une autre, c'est bien de savoir pourquoi.

Reply

Marsh Posté le 04-08-2004 à 16:46:31    

Reply

Marsh Posté le 04-08-2004 à 22:09:52    

mynab a écrit :

non comme ca:
 

Code :
  1. template<typename X> class singleton
  2. {
  3. public:
  4.     static X& get()
  5. {
  6.  static X obj;
  7.  return obj;
  8. }
  9. protected:
  10. singleton() {}
  11. };
  12. class X : public singleton<X>
  13. {
  14. protected:
  15. X() {}
  16. };


 
Tu n'as pas besoin de mettre inline a partir du moment ou la methode est implemetee dans la definition de la classe...


 
Quelle simplification ! Par contre, est il tjs possible de masquer le constructeur de la classe dérivée (protected) en utilisant ce template de singleton ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 05-08-2004 à 12:07:50    

Non tu es oblige de remettre le constructeur dans la classe derivee... Sinon quelqu'un pourra construire un objet de type X. Mais tu n'as pas besoin de deriver la classe si tu n'as rien a y ajouter. Tu peux direcement appeler: singleton<int>::get() par exemple. Ou pour faire plus simple tu peux faire un typedef sur singleton<int>.


Message édité par mynab le 05-08-2004 à 12:08:52
Reply

Marsh Posté le 05-08-2004 à 13:58:26    

il y a un problème par contre si 2 classes utilisent singleton<int> indépendemment, en effet elles travailleraient sur la meme variable...


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-08-2004 à 14:48:47    

faites une factory

Reply

Marsh Posté le 05-08-2004 à 15:15:37    

tu saurais ou trouver de la doc expliquant ce genre de design ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-08-2004 à 15:30:05    

BlackGoddess a écrit :

il y a un problème par contre si 2 classes utilisent singleton<int> indépendemment, en effet elles travailleraient sur la meme variable...


 
ben c'est pas le but d'un singleton?

Reply

Marsh Posté le 05-08-2004 à 15:39:32    

cherche design pattern sur le forum et google
cherche factory singleton ensuite

Reply

Marsh Posté le 05-08-2004 à 15:45:55    

je crois que y a un exemple dans TIC++ de B Eckel

Reply

Marsh Posté le 05-08-2004 à 18:27:46    

Ce que je voulais dire...
 

Code :
  1. template<typename X> class singleton 
  2. public:
  3. static X& get()
  4. {
  5. static X obj;
  6. return obj;
  7. }
  8. protected:
  9. singleton() {}
  10. }; 
  11. class X : public singleton<X>
  12. {
  13. protected:
  14. X() {}
  15. };
  16. int main()
  17. {
  18.   X& x( X::get() );
  19. }


 
ne compile pas :  
 
In static member function `static X& singleton<X>::get() [with X = X]' `X::X()' is protected within this context... blabla.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 05-08-2004 à 18:41:23    

colle un friend

Reply

Marsh Posté le 05-08-2004 à 21:01:05    

Ok. Mais, ajouter friend singleton<X> dans la déclaration de X est un peu contraignant.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 05-08-2004 à 21:02:16    

xterminhate a écrit :

Ok. Mais, ajouter friend singleton<X> dans la déclaration de X est un peu contraignant.


 
non c'est le contraire :D
 

Code :
  1. template<typename X> class singleton 
  2. {
  3. friend class X;
  4. public:
  5. static X& get()
  6. {
  7. static X obj;
  8. return obj;
  9. }
  10. protected:
  11. singleton() {}
  12. };


Message édité par schnapsmann le 05-08-2004 à 21:05:00

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 05-08-2004 à 21:09:33    

ben ça sert à rien ça, puisque X a déjà accès :o
 
friend class singleton<X> est ok
 
à toi de savoir ce que tu fais

Reply

Marsh Posté le 05-08-2004 à 21:10:12    

schnapsmann a écrit :

non c'est le contraire :D
 

Code :
  1. template<typename X> class singleton 
  2. {
  3. friend class X;
  4. public:
  5. static X& get()
  6. {
  7. static X obj;
  8. return obj;
  9. }
  10. protected:
  11. singleton() {}
  12. };



 
Etonnant, tu as quel compilateur ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 05-08-2004 à 21:11:55    

merde je voyais private et non protected là


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 05-08-2004 à 22:36:03    

xterminhate a écrit :

Ce que je voulais dire...
 

Code :
  1. ...
  2. int main()
  3. {
  4.   X& x( X::get() );
  5. }


 
ne compile pas :  
 
In static member function `static X& singleton<X>::get() [with X = X]' `X::X()' is protected within this context... blabla.


 
Ben c'est normal... je ne comprends pas trop ce que tu veux faire avec l'appel que tu fais dans le main...
 
X derive de singleton<> et est donc un singleton. Tu essaies donc de creer une deuxieme instance x de ton singleton. C'est normal que ca ne compile pas puisque en faisant un singleton c'est justement de que tu demandes au compilo: t'interdire de creer plusieurs instances de ton singleton!
 
Si tu veux creer un singleton sur la classe X alors il faut faire:
 

Code :
  1. class X
  2. {
  3.     friend class singleton<X>;
  4. protected:
  5.     X() { // ce que tu veux }
  6. };


 
et apres tu accedes a singleton<X> et voila!


Message édité par mynab le 05-08-2004 à 22:36:38
Reply

Marsh Posté le 06-08-2004 à 07:29:12    

mynab a écrit :

Ben c'est normal... je ne comprends pas trop ce que tu veux faire avec l'appel que tu fais dans le main...


 
Dans le main, je souhaite acceder à l'instance unique de mon singleton de X. C'est un cas d'utilisation parmi tant d'autres. Le but etait bien de faire un modèle de singleton utilisable.
 
A mon sens, le rôle de singleton<X>::get() est de retourner une référence unique. Donc l'appel dans le main, ne multiplie pas les instances de mon singleton de X! Corriges moi si je fais une erreur.
 
D'ailleurs, appeler x::get ou singleton<x>::get revient au même.
 

Code :
  1. int main()
  2. {
  3. {
  4. X& y1( X::get() );
  5. }
  6. X& y2( X::get() );
  7. X& y3( X::get() );
  8. X& y4( X::get() );
  9. X& y5( X::get() );
  10. X& x1( singleton<X>::get() );
  11. X& x2( singleton<X>::get() );
  12. {
  13. X& x3( singleton<X>::get() );
  14. }
  15. X& x4( singleton<X>::get() );
  16. // &y1 = &y2 = &y3 = ... = &x1 = & x2 = ....
  17. }


 

mynab a écrit :


X derive de singleton<> et est donc un singleton. Tu essaies donc de creer une deuxieme instance x de ton singleton. C'est normal que ca ne compile pas puisque en faisant un singleton c'est justement de que tu demandes au compilo: t'interdire de creer plusieurs instances de ton singleton!


 
Non. Je ne vois pas ce qui est normal. Comment arriverais tu à utiliser le modèle que tu m as donné sans ajouter le friend ? [:airforceone]  
 
Merci.


Message édité par xterminhate le 06-08-2004 à 07:30:11

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-11-2004 à 18:30:22    

Voila mon singleton, dites moi ce que vous en pensez:
 

Code :
  1. #ifndef SINGLETON_H
  2. #define SINGLETON_H
  3. #include <memory>
  4. template<typename T>
  5. class Singleton {
  6. public:
  7. static T & getInstance() {
  8.  static std::auto_ptr<T> instance;
  9.  if (!instance.get()) {
  10.   instance.reset(new T);
  11.  }
  12.  return *instance.get();
  13.  /* Sans auto_ptr donc fuite memoire.
  14.  static T * instance;
  15.  if (!instance) {
  16.   instance = new T;
  17.  }
  18.  return *instance;
  19.  */
  20. }
  21. protected:
  22. Singleton() { }
  23. virtual ~Singleton() { }
  24. Singleton(const Singleton & ) { }
  25. Singleton & operator=(const Singleton & ) { }
  26. };
  27. #endif //SINGLETON_H


 
Et un exemple d'utilisation de la classe:

Code :
  1. #include "Singleton.h"
  2. #include <iostream>
  3. using namespace std;
  4. class Toto : public Singleton<Toto> {
  5. friend class Singleton<Toto>;
  6. public:
  7. void sayHello() const {
  8.  cout << "Hello World!" << endl;
  9. }
  10. protected:
  11. Toto() {
  12.  _counter += 1;
  13.  cout << "Initialization: " << _counter << endl;
  14. }
  15. private:
  16. static int _counter;
  17. };
  18. int Toto::_counter = 0;
  19. int main() {
  20. Toto & toto1 = Toto::getInstance();
  21. toto1.sayHello();
  22. Toto & toto2 = Toto::getInstance();
  23. toto2.sayHello();
  24. }


 
J'ai compile avec la ligne suivante:
g++ -g -ansi -Wall -pedantic main.cpp
 
Et valgrind me dit:


valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./a.out
==7364== Memcheck, a memory error detector for x86-linux.
==7364== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
==7364== Using valgrind-2.3.0.CVS, a program supervision framework for x86-linux.
==7364== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
==7364== For more details, rerun with: -v
==7364==
Initialization: 1
Hello World!
Hello World!
==7364==
==7364== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 17 from 1)
==7364== malloc/free: in use at exit: 0 bytes in 0 blocks.
==7364== malloc/free: 1 allocs, 1 frees, 4 bytes allocated.
==7364== For counts of detected errors, rerun with: -v
==7364== No malloc'd blocks -- no leaks are possible.


 
Et si je n'utilise pas auto_ptr (le code en commentaire), valgrind me dit:


valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./a.out
==7371== Memcheck, a memory error detector for x86-linux.
==7371== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
==7371== Using valgrind-2.3.0.CVS, a program supervision framework for x86-linux.
==7371== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
==7371== For more details, rerun with: -v
==7371==
Initialization: 1
Hello World!
Hello World!
==7371==
==7371== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 17 from 1)
==7371== malloc/free: in use at exit: 4 bytes in 1 blocks.
==7371== malloc/free: 1 allocs, 0 frees, 4 bytes allocated.
==7371== For counts of detected errors, rerun with: -v
==7371== searching for pointers to 1 not-freed blocks.
==7371== checked 2227148 bytes.
==7371==
==7371== 4 bytes in 1 blocks are still reachable in loss record 1 of 1
==7371==    at 0x1B904730: operator new(unsigned) (vg_replace_malloc.c:132)
==7371==    by 0x80489D6: Singleton<Toto>::getInstance() (Singleton.h:24)
==7371==    by 0x80488F0: main (main.cpp:29)
==7371==
==7371== LEAK SUMMARY:
==7371==    definitely lost: 0 bytes in 0 blocks.
==7371==    possibly lost:   0 bytes in 0 blocks.
==7371==    still reachable: 4 bytes in 1 blocks.
==7371==         suppressed: 0 bytes in 0 blocks.


Message édité par tanguy le 14-11-2004 à 18:33:19
Reply

Marsh Posté le 14-11-2004 à 20:53:04    

Ce modèle ci ne convenait pas ?

Code :
  1. template< typename X >
  2. struct singleton 
  3. static X& instancier()
  4. {
  5.  static X obj;
  6.  return obj;
  7. }
  8. virtual ~singleton() {}
  9. protected:
  10. singleton() {}
  11. singleton( const singleton& ) {}
  12. singleton& operator=( const singleton& ) {}
  13. };


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed