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 :

Classe singleton ?


Sujet :

C++

  1. #1
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut Classe singleton ?
    Yo!

    Je voudrais savoir si la classe suivante est bien un singleton. Surtout au niveau de l'appel de la fonction instance(). Est ce que cela consiste bien en un singleton.

    Merci

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    class Statique
    {
    public:
        static Statique* instance()
    	{
    		static Statique static_;
    			 return &static_;
    	}
    	 ~Statique()
    	{
    	  //  delete T;
    		std::cout<<"Statique::dtor default"<<endl; 
    	};
    	 void set_o(int arg1)
    	{
    	    o=arg1;
    	}
    private:
    	Statique(const Statique& right)
    	{
    		std::cout<<"Statique::ctor copy"<<endl;  
    		o=right.o;
    		c=right.c; 
    	};
    	Statique():o(0),c('d')
    	{ 
    	//	T[0]=0;
    	//	T[1]=1;
    		std::cout<<"Statique::ctor default"<<endl; 
    	};
     
       private:
    		int o;
    		char c;
    	//	char *T;
    };
     
    int main(){
     
    	Statique* ind(Statique::instance());
     
    	Statique* obj2(Statique::instance());
     
    	ind->set_o(99);
    }

  2. #2
    Membre averti Avatar de Dalini71
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2008
    Messages
    181
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2008
    Messages : 181
    Points : 343
    Points
    343
    Par défaut
    A vue de nez ca à l'air bon.

    Par contre pourquoi implémenter le constructeur par copie ? Ça n'a pas vraiment de sens vu que tu ne peux pas avoir plus d'une instance de ta classe.

    Plus de détails sur les Singletons dans FAQ C++.

  3. #3
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Par contre pourquoi implémenter le constructeur par copie ?
    Par habitude. Sinon, j'ai fait ceci:

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    enum AS{
    	Coeur, 
    	Trefle,
    	Carreau
    };
     
    class Gr
    {
    public:
    	Gr()
    	{
    		cout<<"std::default ctor";
    	}	
    	Gr(const Gr& right)
    	{
    		cout<<"std::copy ctor"; 
    	}
    	Gr(ASarg1, std::string arg2):f(arg1),g(arg2)
    	{
    	}
    	~Gr()
    	{
    		std::cout<<("ee");
    	}
    private:
    	AS f;
    	std::string g;
     
    };
     
    static const Gr Tab[2]={
    	Gr(AS::Carreau,"Carreau"),
    	Gr(AS::Coeur, "Coeur"),
    };
    En fait je veux créer un tableau statique ("globlal" donc) qui contient des éléments de la classe Gr. Lorsque je crée ce tableau, le destructeur est appelé à chaque fois, ce qui est normal. Je n'arrive pas à rendre statique les
    élements du tableau, bien que le tableau le soit.

  4. #4
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Quand on fait ca par exemple,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    static int tab[]={1,4...}
    alors c'est sur que les éléments du tableau ne vont pas être supprimés une fois que le tableau sera instancié dans la zone mémoire réservée au variable statiques.

    Avec mon ancien code, les éléments du tableau étaient deletés un fois le tableau crée. Ce qui est normal en fait.
    J'ai fait ceci:

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    enum AS{
    	Coeur, 
    	Trefle,
    	Carreau
    };
     
    class Gr
    {
    public:
    	static Gr* instance(AS f, std::string g)
    	{		cout<<"std::default ctor"<<endl;
     
    	 Gr* fuck=new Gr(f,g);
    	 return fuck;
     
    	}
    	Gr()
    	{
    		cout<<"std::default ctor"<<endl;
    	}
    	Gr(const Gr& right) 
    	{
    		cout<<"std::copy ctor"<<endl; 
    	}
     
    	Gr(AS arg1, std::string arg2):f(arg1),g(arg2)
    	{
    		std::cout<<("ctor ")<<endl;
    	}
    	~Gr()
    	{
    		std::cout<<("dtor ")<<endl;
    	}
    private:
    	AS f;
    	std::string g;
     
    };
    static const Gr* Tab[2]={
    	Gr::instance(AS::Carreau,"Carreau"),
    	Gr::instance(AS::Coeur, "Coeur"),
    };
    Mais j'ai alloué sur de la mémoire sur le tas. Ne risque t-on pas d'avoir de la memory leak, étant donné que je n'appelle pas l'operateur delete?
    Merci

  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
    Salut,

    Tu l'as surement déjà lu sur le forum, je me contente donc juste d'un rappel, mais, les variables statiques (quelle que soit leur forme) CEYMAL...

    La question que je me pose dés lors, c'est
    pourquoi crois tu avoir besoin d'un tableau statique de cartes
    Au pire, tu crées une collection de pointeurs sur des cartes allouées dynamiquement (pour prendre la responsabilité de la durée de vie des cartes ) (je verrais bien une liste plutot qu'un tableau ) qui appartient (je parle de la collection ) à une classe (appelons la "Sabot" par facilité ) dont la responsabilité est... de gérer les cartes, à savoir
    • de les sortir "à la demande" en début (ou en cours) de partie
    • de les récupérer en fin de partie / tour


    La seule classe disposant du sabot est le croupier (ou la banque) qui va décider de prendre une carte dans le sabot pour la donner à un joueur ou à une main.

    En fonction du jeu que tu veux créer, il n'est pas exclu que différentes classes puissent s'échanger les cartes, en en donnant par-ci en en prenant par là ou en en demandant au croupier (à la banque).

    Mais, une chose est sure : quand le tour (ou la partie, selon le jeu que tu crées ) est fini, le croupier récupérera l'ensemble des cartes l'ensemble des cartes qui sont sorties du sabot pour les y remettre, en vue de préparer le prochain tour, la prochaine partie.

    Lorsque tu lancera ton application, le croupier sera fatalement créé durant la phase d'initialisation (avant meme qu'un joueur ne se soit joint à la partie), et donc le sabot dont il dispose sera, lui aussi créé.

    Comme le sabot sera créé, l'ensemble des cartes nécessaires pour le remplir sera, lui aussi, créé et, inversement, lorsque tu décidera de quitter l'application, le croupier sera détruit dans la phase de "nettoyage" (une fois que tous les joueurs auront quitté la partie), et le sabot dont il dispose le sera d'office également.

    C'est à ce moment là que toutes les cartes contenues dans le sabot seront elles aussi détruites

    En gros, ton sabot n'a absolument aucun besoin d'être un singleton, vu qu'il ne doit etre connu que du croupier, qui ne doit lui-même absolument pas être un singleton, vu qu'il doit y en avoir un (différent !!!) pour chaque table qui n'a elle non plus aucune raison d'être un singleton vu que tu pourrais (pourquoi pas) prévoir d'avoir plusieurs tables actives en meme temps dans ton application.

    Enfin, ce qui contient les différentes tables n'aura sans doute aucune raison d'être un singleton car ce sera sans doute ce qui sert d'interface vers l'extérieur (ce qui accepte l'arrivée d'un nouveau joueur et lui propose les différentes tables auxquelles il peut s'assoir, en fonction des places disponible), qui sera créé dans main et qui disposera sans doute d'une fonction run, appelée depuis main, dont on ne sortira plus tant que l'application tournera

    As tu compris pourquoi il est inutile de créer un quelconque tableau statique de cartes ou un quelconque singleton
    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
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Au pire, tu crées une collection de pointeurs sur des cartes allouées dynamiquement (pour prendre la responsabilité de la durée de vie des cartes ) (je verrais bien une liste plutot qu'un tableau ) qui appartient (je parle de la collection ) à une classe (appelons la "Sabot" par facilité ) dont la responsabilité est... de gérer les cartes, à savoir
    Ok, je vois. Je peux créer une variable statique dans la classe, qui sera initialisée tout au début, avant le début du jeu comme tu dis.
    Donc on peut faire ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Gr
    {
    public:
    	static  const Gr* Tab[];
    Mais, une chose est sure : quand le tour (ou la partie, selon le jeu que tu crées ) est fini, le croupier récupérera l'ensemble des cartes l'ensemble des cartes qui sont sorties du sabot pour les y remettre, en vue de préparer le prochain tour, la prochaine partie.
    Ca ca doit vouloir dire que les éléments du tableau crées dynamiquement sont détruits à la fin du programme.

    As tu compris pourquoi il est inutile de créer un quelconque tableau statique de cartes ou un quelconque singleto
    Un singleton oui, mais je vois pas ce qui m'empeche de fiare un static.

  7. #7
    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 deubelte Voir le message
    Ok, je vois. Je peux créer une variable statique dans la classe, qui sera initialisée tout au début, avant le début du jeu comme tu dis.
    Donc on peut faire ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Gr
    {
    public:
    	static  const Gr* Tab[];


    Ca ca doit vouloir dire que les éléments du tableau crées dynamiquement sont détruits à la fin du programme.


    Un singleton oui, mais je vois pas ce qui m'empeche de fiare un static.
    D'abord, parce que tu n'a aucun besoin d'avoir un tableau statique: il ne doit y avoir qu'une seule classe qui le manipule, et tu n'as aucun besoin d'y faire référence ailleurs

    Ensuite parce que cela t'interdit tout un pan d'évolutions possibles (il te sera impossible de décider d'avoir deux tables distinctes si ta collection de cartes est statique : elle serait alors ... partagées par toutes les tables, ce qui n'est absolument pas intéressant )

    Enfin, parce que les variables statiques posent énormément de problèmes au niveau de la pureté et de la réentrance des fonctions (avec quantité d'effets de bord indésirables dans bien des cas)

    Si une donnée doit etre statique, elle doit etre constante pour éviter les problèmes d'effet de bord (par exemple, la valeur npos que l'on trouve dans la classe std::string), un tableau de cartes constant n'a strictement aucun intérêt

    Il faut bien te dire que variable statique == variable globale et que les variables globales sont la pire des choses que tu puisse avoir car tu perds de facto tout contrôle sur les changements d'état qu'elle peut subir (entre autres dans un contexte multi-threadé, mais pas seulement).

    De plus, l'idée même d'un tableau (et surtout d'un tableau de taille fxe comme tu semble vouloir en créer un) n'est, à mon sens, pas des plus opportunes pour représenter l'ensemble des cartes.

    En effet, tu vas créer tes 52 (ou plus, ou moins, en fonction du jeu de cartes que tu veux créer) cartes, puis les cartes vont bouger, être données à des joueurs, être mises au tapis, être récupérées, être mélangées et tout ce que tu veux...

    La quantité de cartes dont ton sabot va disposer va donc varier en cours de jeu, ce qui ira à l'encontre même de l'idée d'utiliser un tableau de taille constante

    Mais il y aura malgré tout une constante d'utilisation: ce sera toujours la carte qui se trouve "en haut" du sabot qui sera donnée en premier, et les cartes récupérées seront d'office placée "en bas" du sabot.

    Gérer cet aspect de l'utilisation des cartes sous la forme d'un tableau t'obligera à garder, au minimum, l'index de la carte se trouvant "au dessus" du sabot et d'être capable de savoir, pour un index donné, si la carte a été distribuée ou non

    Or, tu n'as absolument pas besoin d'avoir un accès aléatoire à tes cartes: toute tentative visant utiliser un accès aléatoire aura pour effet de faire baisser les performances d'obtention d'une carte de manière proportionnelle au nombre de cartes distribuées.

    En effet, plus il y a de cartes distribuées, plus tu risques, en voulant utiliser un index choisi de manière aléatoire, de tomber sur celui d'une carte qui a déjà été distribuée, et le fait que ce soit arrivé une fois ne te garanti pas que cela n'arrivera plus avec le prochain index choisi aléatoirement

    Voilà pourquoi il vaut mieux disqualifier le tableau comme collection de cartes...

    Etant donné les besoins que l'on a déjà déterminé (on prend d'office la carte "au dessus" et on remet les cartes "en dessous"), il ne nous reste que deux solutions : la file ou la liste.

    Seulement, il faudra envisager de mélanger les cartes (au moins lors de l'initialisation, et peut etre en cours de partie)...

    Nous devons donc, lors du mélange (et uniquement à cette occasion) pouvoir manipuler les cartes qui se trouvent "au milieu" (ou du moins en dessous de la première et au dessus de la dernière )...

    La file est donc elle aussi disqualifiée pour cet usage

    Il ne reste donc qu'un seul type de collection qui offre toutes les capacités nécessaires : la liste

    De cette manière, lorsque tu dois distribuer une carte, tu utilise un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    hand->addCard(*(list_.front()));
    list_.pop_front;
    lorsque tu veux récupérer les cartes, tu peux travailler sur un mode proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<iterator>
    void sabot::getCardsBack(iterator begin, iterator end)
    {
        list_.insert(list_.end(),begin, end);
    }
    et le mélange pourrait ressembler à quelque chose comme (c'est surement perfectible )
    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
    void sabot::melange()
    {
        for(int i = 0;i<nombreDechanges;++i)
        {
            int first = /* choix aléatoire d'une valeur */
            int second = /* choix aléatoire d'une valeur */
            std::list<Carte *>::iterator iterFirst=list_.begin();
            std::list<Carte *>::iterator iterSecond=list.begin();
            for(int j=0;j<first;++j)
                ++iterFirst;
            for(int j=0;j<second;++j)
                ++iterSecond;
            std::iter_swap( iterFirst, iterSecond );
        }
    }
    Comme le sabot n'existe que pour une table donnée et que le croupier est seul à pouvoir décider de prendre une carte dans le sabot de la table dont il a la charge, tu n'as strictement aucun intérêt à... gérer ta liste de (pointeurs sur) cartes sous la forme d'une variable statique !!!!

    et ce, d'autant plus que, si tu décide de créer une deuxième table, il faut qu'elle dispose de son sabot propre avec... ses propres cartes, et qu'il est hors de questions de mélanger les cartes du sabot de la table 1 avec celles du sabot de la table 2
    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

  8. #8
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Par rapport aux choix du conteneur, pourquoi ne pas utiliser un deque, plutôt qu'une liste ?
    - Le mélange est considérablement simplifié ( le deque possède des itérateurs à accès aléatoire, donc utilisable avec std::random_shuffle )
    - L'insertion en début et en fin a plus ou moins la meme complexité que pour les listes
    - Il n'y a pas besoin de l'insertion au milieu ou de la fusion de deux conteneurs (qui sont quand même les deux avantages principaux des listes sur les deques)
    Dernière modification par koala01 ; 10/12/2011 à 13h50.

  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 Joe Dralliam Voir le message
    Bonjour,
    Par rapport aux choix du conteneur, pourquoi ne pas utiliser un deque, plutôt qu'une liste ?
    - Le mélange est considérablement simplifié ( le deque possède des itérateurs à accès aléatoire, donc utilisable avec std::random_shuffle )
    - L'insertion en début et en fin a plus ou moins la meme complexité que pour les listes
    - Il n'y a pas besoin de l'insertion au milieu ou de la fusion de deux conteneurs (qui sont quand même les deux avantages principaux des listes sur les deques)
    Il est vrai que je n'y avais, tout simplement, pas pensé ...

    Ceci dit, tu m'as fait réaliser qu'il était tout à fait possible d'améliorer encore grandement le design en faisant intervenir une classe supplémentaire dont la seule responsabilité serait de mélanger les cartes contenues par le "sabot"

    Je m'explique : Je me suis basé sur le fait que la responsabilité du "sabot" était de gérer les cartes du jeu, et que le mélange des cartes faisait "naturellement" partie de cette gestion.

    Mais nous pourrions prendre une granularité plus fine encore, et estimer que le sabot ne fait, vraiment, que gérer les cartes :
    • les construire quand il est construit,
    • les détruire quand il est détruit,
    • les fournir à la demande,
    • les récupérer chaque fois que nécessaire
    On peut alors (éventuellement) demander au sabot que les cartes soient mélangées, mais elles pourraient parfaitement l'être par "quelqu'un d'impartial" comme... un mélangeur de carte dont ce serait la seule responsabilité

    Le sabot pourrait alors maintenir les cartes dans une file (queue) car, hormis pour le mélange, nous travaillerons effectivement sur le principe de la file, et nous profiterions du constructeur de celle-ci pour récupérer les cartes une fois mélangées

    Le mélangeur utiliserait, quant à lui, une deque (ou pourquoi pas un tableau ) pour pouvoir effectuer son travail

    Cela se traduirait sous une forme proche de
    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
    23
    24
    class Sabot
    {
        /* comme le mélangeur n'est à utiliser que par le sabot, ca peut
         * etre une classe imbriquée :D
         */
        class shuffler
        {
            template <class iterator>
            std::vector<Carte*> operator()(iterator begin, iterator end)
            {
                 std::vector<Carte*> temp(begin, end);
                 std::random_shuffle(temp.begin(),temp.end());
                 return temp();
            }
        };
        public:
            void shuffle()
            {
                queue_=std::queue(shuffler()(queue_.begin(),queue_.end());
            }
            /* les autres fonctions attendues */
        private:
            std::queue queue_;
    };
    On se paye, bien sur, quelques copies, mais, dans l'ensemble, ce ne sont jamais que des pointeurs qui sont copiés, et il n'y en a que maximum 52 par jeu de cartes utilisé
    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. Vecteurs non remplis, et classe Singleton.
    Par Floréal dans le forum SL & STL
    Réponses: 8
    Dernier message: 23/05/2007, 09h28
  2. Réponses: 14
    Dernier message: 02/02/2006, 18h32
  3. Implemetation de la classe Singleton
    Par lepoutho dans le forum C++
    Réponses: 6
    Dernier message: 20/08/2005, 11h46
  4. [introspection][singleton] introspetion de classe à singleton
    Par Jaxofun dans le forum API standards et tierces
    Réponses: 7
    Dernier message: 18/08/2005, 09h59
  5. fonctionnement de la classe Singleton
    Par lepoutho dans le forum C++
    Réponses: 11
    Dernier message: 04/08/2005, 09h28

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