IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Singleton et variable de classe


Sujet :

C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Singleton et variable de classe
    Bonjour,

    J'ai pu mettre en place l'instance unique d'une classe grâce au système de singleton disponible ici : http://cpp.developpez.com/faq/cpp/?p...LASS_singleton

    J'arrive à récupérer mon instance dans toutes mes classes, mais j'aimerais maintenant pouvoir mettre mon instance unique dans une variable d'une de mes classes pour ne pas avoir à récupérer l'instance dans chaque méthode.

    Ma classe singleton est la classe de Log. Pour récupérer l'instance unique, je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Log& log = Log::getInstance();
    Dans l'une de mes classes, j'ai déclaré cette variable privée (log):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class MaClasse
    {
    	private:
    		MaClasse();
    		~MaClasse();
    		MaClasse (const MaClasse&);
    		MaClasse& operator= (const MaClasse&);
     
     
    	public:	
    		static MaClasse& getInstance();
    		void start();
    		void loadConfig();
     
     
    	private:
    			//Instance
    		static MaClasse instance;
     
    		static Log& log;
     
    };
    Et j'ai ajouté dans mon constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    MaClasse::MaClasse()
    {
     
    		//Chargement de la configuration
    	loadConfig();
     
    	loggg = Log::getInstance();
    }
    Mais j'ai l'erreur suivante :

    error: 'Log& Log::operator=(const Log&)' is private
    error: within this context
    Merci d'avance pour votre aide

  2. #2
    screetch
    Invité(e)
    Par défaut
    On ne peut pas affecter a une référence comme ca, il faut l'initialiser correctement. La variable globale etant initialisée au lancement du programme, soit tu l'instancies là, soit tu mets un pointeur a la place (avec tous les risques que ca comporte)

    Apparemment, MaClasse est aussi un signleton, je rappelle que le singleton n'est pas considéré comme un design pattern de très bonne qualité hein...

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Citation Envoyé par screetch Voir le message
    On ne peut pas affecter a une référence comme ca, il faut l'initialiser correctement. La variable globale etant initialisée au lancement du programme, soit tu l'instancies là, soit tu mets un pointeur a la place (avec tous les risques que ca comporte)
    Je débute et je n'ai pas tout compris. Est ce que vous pourriez me donner une manière d'avoir accès à l'instance unique dans une de mes classes, ici MaClasse par exemple sans avoir à récupérer l'objet dans chaque méthode par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Log& log = Log::getInstance();
    . De plus, j'ai lu que le système par pointeur est beaucoup plus dangereux donc je préfère utiliser les références.

    Citation Envoyé par screetch Voir le message
    Apparemment, MaClasse est aussi un signleton, je rappelle que le singleton n'est pas considéré comme un design pattern de très bonne qualité hein...
    Il est pourtant cité et expliqué ici : http://come-david.developpez.com/tutoriels/dps/
    Dans ce cas si ce n'est pas une bonne pratique, comment faire pour accéder à des variables d'une instance dans plusieurs classes ? Ou encore dans le cas de ma classe de Log, cela permet de ne pas ouvrir / fermer le fichier de log plusieurs fois et en même temps.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 243
    Points : 415
    Points
    415
    Par défaut
    Je débute et je n'ai pas tout compris. Est ce que vous pourriez me donner une manière d'avoir accès à l'instance unique dans une de mes classes, ici MaClasse par exemple sans avoir à récupérer l'objet dans chaque méthode par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Log& log = Log::getInstance();
    .
    "Log::getInstance()" est la définition même du singleton...

    De plus, j'ai lu que le système par pointeur est beaucoup plus dangereux donc je préfère utiliser les références.
    Comme cela a déjà été dit, une référence doit forcement être initialisée à sa création, c'est la définition même d'une référence...



    Il est pourtant cité et expliqué ici : http://come-david.developpez.com/tutoriels/dps/
    Dans ce cas si ce n'est pas une bonne pratique, comment faire pour accéder à des variables d'une instance dans plusieurs classes ? Ou encore dans le cas de ma classe de Log, cela permet de ne pas ouvrir / fermer le fichier de log plusieurs fois et en même temps.
    Un singleton n'est rien d'autre qu'une variable globale, à ceci près que tu contrôles sa destruction et retarde (ou évite) sa construction.
    Cela peut-être pratique mais certains l'utilise très mal. Dans ton cas ça a l'air d'être la bonne solution.

    Qu'est-ce qui te déranges tant avec "Log::getInstance()" ?

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par blopp Voir le message
    Il est pourtant cité et expliqué ici : http://come-david.developpez.com/tutoriels/dps/
    Dans ce cas si ce n'est pas une bonne pratique, comment faire pour accéder à des variables d'une instance dans plusieurs classes ? Ou encore dans le cas de ma classe de Log, cela permet de ne pas ouvrir / fermer le fichier de log plusieurs fois et en même temps.
    Salut,

    Le meilleur moyen d'assurer l'unicité d'instance d'une classe est encore... de veiller à n'en créer qu'une seule instance, et de la passer (par référence, éventuellement constante) à toute fonction qui en aura besoin

    Bien souvent, on constate que le singleton n'est pas si "universel" que cela dans le code, et qu'il est donc dommage d'en arriver à créer quelque chose qui ne sera détruit que... lors de la fermeture de l'application.

    De plus, il faut avouer que la syntaxe en elle même permettant d'accéder à l'instance unique (
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonSingleton::instance()/*... */
    )est particulièrement éloignée de la syntaxe habituellement utilisée en OO (
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonObjet obj(/* ... */);
    )

    Une solution élégante pour éviter le singleton consiste à inverser l'ordre de pensée et, au lieu de partir du principe de
    je ne veux jamais avoir plus d'une instance de ma classe
    de partir de l'idée que
    Quelle que soit le nombre d'instances de ma classe que je créerai, je veux qu'elles partagent toutes les mêmes données internes
    Il est particulièrement facile d'arriver à ce résultat, car il suffit de veiller à ne déclarer que des membres statiques dans la classe, tout en laissant les fonctions membres (et principalement les fonctions publiques) sous leur forme "non statique" classique.

    Voilà le principe de ce que l'on appelle le "monostate pattern", qui prend donc une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MaClass
    {
        public:
            /* que des fonctions non statiques (pouvant être constantes en cas
             * de besoin
             */
        private:
            /* que des membres statiques */
    };
    qui sera utilisée exactement comme s'il s'agissait d'une classe "classique" (sans que cela ne vienne distraire l'utilisateur, et sans qu'il ne se rende compte que toutes les instances partagent les même données )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    MaClass leGestionnaire;
    leGestionnaire.faisCeci();
    leGestionnaire.faisCela();
    /*... */
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par blopp Voir le message
    Il est pourtant cité et expliqué ici : http://come-david.developpez.com/tutoriels/dps/
    Dans ce cas si ce n'est pas une bonne pratique, comment faire pour accéder à des variables d'une instance dans plusieurs classes ? Ou encore dans le cas de ma classe de Log, cela permet de ne pas ouvrir / fermer le fichier de log plusieurs fois et en même temps.
    On trouve tout et n'importe quoi sur le net, donc il faut garder un esprit critique. Un singleton a deux aspects:
    1) il n'y a qu'une seule instance
    2) tout le monde la connait

    ces deux aspects sont criticables. commencons dans l'ordre

    1) il n'y a qu'une seule instance
    dans 100% des cas que j'ai vu, avoir une seule instance possible de quelque chose a conduit a une limitation plus tard. Dans ma boite, mes collègues ont abusé de variables globales et de singleton, basé sur le fait qu'"on ne peut avoir qu'un seul joueur derrière l'ecran". Et puis un jour on a demandé si le jeu supporterait le multiplayer sur la même machine, et les devs ont répondu "non, parce qu'on est con, on a pensé que ca arriverait jamais". Bon, ptêtre ils l'ont pas dit cmme ca, ptêtre c'est moi qui l'ai pensé tous haut.
    Exemple 2: dans un jeu, le système de rendu a tendance a être un singleton, ce qui m'agace 8mais il ne peut y avoir qu'un seul rendu du jeu!!!)
    Récemment, sur mon projet, qui a un renderer OpenGL et DirectX sous forme de plugin, j'ai essayé de charger les deux plugins en même temps.
    Et tu sais ce que ca a fait? non, ca a pas crashé du tout, ca a juste affiché deux fois la même scène, dans deu fenêtres différentes, une en OpenGL et une en DirectX. Ca sert a rien, mais ca veut dire que le singleton n'est pas une nécessité


    et bon alors ma question est pourquoi tu veux FORCER une seule instance. Ca part souvent d'un principe foireux; c'est pour cacher du code qui est mauvais, qui est incapable de fonctionner si tu crées deux instances. Alors tu caches la poussière sous le tapis, tu fais un singleton.



    2) tout le monde la connait

    probablement la pire raison; pourquoi tout le monde la connait? il me semble que ca cache la encore une erreur, un truc qui ne va pas.

    tu crées une dépendance forte entre une classe et toute les autres (argh!!!) et du coup, un test unitaire n'est plus unitaire, c'est un test... dual? ou je ne sais pas.
    Si ta classe de log plante pour une raison quelconque, tous tes tests unitaires vont péter. Je trouve ca intolérable.







    Pour un systeme de log, je pense que c'est peut être ce qui a le plus de sens sous forme de singleton. Mais tu prives les gens de la possibilité de faire leur log "privé". Par exemple, la partie réseau de ton application réseau pourrait utiliser un log différent dans un fichier différent pour ne pas polluer le log principal. Tu pourrais avoir un système de log pour chaque gros module, etc etc.


    Pour tout le reste, revoit le design et demande toi pourquoi tout le monde le connait et pourquoi il ne peut y avoir qu'une instance. Il vaut mieux résoudre ces deux problèmes que de faire un singleton.







    Et pour répondre plus précisément a ta question, il n'y a pas de moyen vraiment propre de faire ce que tu veux sans que ca crée d'autres problèmes (que je ne peux pas expliquer ici sans rentrer dans d'obscurs détails)
    mais pour faire simple, une référence doit être initialisée dés le départ, et elle va pointer vers la même resource pendant toute sa durée de vie.
    ta référence vers le log a une portée globale. Sa durée de vie est "depuis le lancement du programme, jusqu'a sa terminaison".
    Cette référence doit donc être initialisée dés le lancement du programme, avant même que la fonction main soit appelée, et elle durera jusqu'après la fonction main.
    c'est possible mais c'est dangereux et ca crée plus de problèmes que ca en résout.

  7. #7
    screetch
    Invité(e)
    Par défaut
    j'ai oublié:

    Citation Envoyé par blopp Voir le message
    De plus, j'ai lu que le système par pointeur est beaucoup plus dangereux donc je préfère utiliser les références.
    ca c'est très sage. Je ne voulais pas insinuer que tu fais tout de travers, et ca ca me semble être très raisonné et tu es sur la bonne voie

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Parfait, merci beaucoup à vous deux !
    J'ai fait des recherches sur le "monostate pattern" et j'ai notamment découvert plusieurs pdf qui comparent le monostate pattern avec le singleton. Ce qui ressort est plutôt en faveur du "monostate pattern", donc j'ai décidé d'utiliser cette solution. Mon but n'est pas de cacher du code ou encore d'empêcher un crash si il y a plusieurs instances, c'est juste que j'ai besoin d'accéder à des variables de l'instance un peu partout dans le programme, qui je sais est unique puisque c'est ma classe de socket qui écoute sur le réseau.
    J'ai donc pu mettre en place un système de "monostate pattern" plutôt que de singleton. J'ai du rajouter une variable d'initialisation (bool) pour ne pas exécuter plusieurs fois le constructeur.
    Par contre je suis obligé de déclarer toutes mes variables statiques dans le début du fichier .cpp, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int maClasse::variable; 
    int  maClasse::autrevariable;
    ...
    Sinon tout fonctionne parfaitement maintenant !

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par blopp Voir le message
    Parfait, merci beaucoup à vous deux !
    J'ai fait des recherches sur le "monostate pattern" et j'ai notamment découvert plusieurs pdf qui comparent le monostate pattern avec le singleton. Ce qui ressort est plutôt en faveur du "monostate pattern", donc j'ai décidé d'utiliser cette solution. Mon but n'est pas de cacher du code ou encore d'empêcher un crash si il y a plusieurs instances, c'est juste que j'ai besoin d'accéder à des variables de l'instance un peu partout dans le programme, qui je sais est unique puisque c'est ma classe de socket qui écoute sur le réseau.
    C'est sans doute déjà le symptôme d'un problème de conception à la base...

    De prime abord, le socket ne devrait être connu que, mettons, par deux classes : une pour l'écouter, l'autre pour y envoyer des informations (formatées par ailleurs).

    Ces deux classes ne devant être connues (sans savoir qu'un socket est utilisé en arrière plan) que par un nombre (relativement) limité de classes afin de "formater" les données reçues (ou à émettre) au travers du socket.

    Chaqune de ces classes devrait, enfin, n'être connues que par un nombre limité d'autre classes qui savent "uniquement" que telle information sera "formatée" et envoyée (ou récupérée) "quelque part" (mais pas forcément vers un socket: ce pourrait aussi être vers un simple fichier texte un "pipe", un autre exécutable, ou que sais-je ) en vue de traitement "externe".

    De cette manière, tu gagnes non seulement en terme de délégation des tâches (chaque objet / fonction ne fait qu'une seule chose, mais il / elle le fait bien) mais aussi en terme d'évolutivité: fais dériver tes classes "émettrice" et "réceptrice" de sorte à ce qu'elles envoyent (reçoivent) les données depuis un fichier, joue avec le polymorphisme, et tu obtiens la possibilité de sauvegarder les informations pour, pourquoi pas, créer un script qui enverra le tout vers le socket "plus tard", ou pour simplement récupérer les informations le lendemain
    Par contre je suis obligé de déclarer toutes mes variables statiques dans le début du fichier .cpp, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int maClasse::variable; 
    int  maClasse::autrevariable;
    ...
    Sinon tout fonctionne parfaitement maintenant !
    Ca, c'est normal
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Accès a des variables de classes
    Par lalouve dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 11/05/2006, 16h48
  2. variable de classe en Python
    Par Thierry Chappuis dans le forum Général Python
    Réponses: 5
    Dernier message: 09/02/2006, 22h06
  3. Variable de classe JPanel
    Par Janitrix dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 11/12/2005, 17h50
  4. débutant:utilisation de variable entre classe
    Par troojan dans le forum MFC
    Réponses: 1
    Dernier message: 07/12/2005, 23h31
  5. Réponses: 6
    Dernier message: 23/09/2005, 12h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo