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 en C++


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé

    Profil pro
    Inscrit en
    Avril 2005
    Messages
    162
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 162
    Par défaut Singleton en C++
    Bonjour,

    Je me suis toujours demande (dans un contexte monothread) pourquoi, pour écrire un singleton Widget, on ne fait généralement pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    static Widget& instance()
    {
      static Widget w;
      return w;
    }
    ou bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    static Widget& instance()
    {
      static Widget* w = new Widget();
      return *w;
    }

    plutôt qu'utiliser un membre static de la classe Widget :

    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
     
    class Widget
    {
    public:
    ...
     
    static Widget& instance()
    {
      if (!w)
      {
        w = new Widget;
      }
      return *w;
    }
    ...
     
    private:
    static Widget* w;
    };
     
    Widget* Widget::w = 0;
    Ce qui est qd même plus long à écrire ...

  2. #2
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Par défaut
    salut,
    dans ton cas tu n'as besoin apparemment que d'une fonction globale ,
    mais si ton singleton propose d'autres services comme la libération de la ressource allouée, dans ce cas une classe est plus pratique qu'une fonction globale.
    la deuxième forme d'allocation de ta ressource peut être obligatoire si elle a besoin d'un contexte précis pour être instanciée. (dépendance avec une autre ressource de l'application).
    donc ça depend de la ressource a partager ,si elle est autonome ou non,
    autre point avec des outils comme intellisense (visual c++) je préfère passer par une classe c'est plus pratique a l'utilisation mais plus long a écrire...

  3. #3
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par vandamme Voir le message
    Bonjour,

    Je me suis toujours demande (dans un contexte monothread) pourquoi, pour écrire un singleton Widget, on ne fait généralement pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    static Widget& instance()
    {
      static Widget w;
      return w;
    }
    C'est le singleton de Meyer.

    Citation Envoyé par vandamme Voir le message
    ou bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    static Widget& instance()
    {
      static Widget* w = new Widget();
      return *w;
    }
    Ca, c'est une des formes canoniques.

    Citation Envoyé par vandamme Voir le message
    plutôt qu'utiliser un membre static de la classe Widget :

    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
     
    class Widget
    {
    public:
    ...
     
    static Widget& instance()
    {
      if (!w)
      {
        w = new Widget;
      }
      return *w;
    }
    ...
     
    private:
    static Widget* w;
    };
     
    Widget* Widget::w = 0;
    Ce qui est qd même plus long à écrire ...
    Et ça, c'est le singleton tel qu'il est présenté dans le GoF95 - la forme canonique de base.

    Chacune des implémentations a sa spécificité (les deux formes canoniques sont équivalentes, mais le destructeur de Widget n'est pas appelé. Le destructeur du singleton de Meyer est appelé, mais il est difficile voire impossible de savoir quand).

    Ensuite, le choix de l'implémentation dépends du projet sur lequel tu travailles. La question de savoir quelle est la forme la plus facile a définir n'a pas véritablement d'intérêt, puisque la bonne réponse à cette question dépends de l'environnement dans lequel le singleton est intégré.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  4. #4
    Membre émérite Avatar de valefor
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    711
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 711
    Par défaut
    Anecdote :

    Avec une vieille implémentation de gcc, sous Solaris, j'ai eu un problème un jour avec ces singletons.

    On faisait un chargement dynamique de bibliothèque.
    De cette bibliothèque on récupérait un singleton.
    On déchargeait la bibliothèque.
    On arrêtait le programme et paf segv (que l'on n'a pas vu dessuite, on a cru pendant longtemps que tout fonctionnait bien).

    Le problème venait que le destructeur du singleton était appelé après déchargement de la lib.

    Avec les versions plus récentes de gcc le problème a été résolu.

  5. #5
    screetch
    Invité(e)
    Par défaut
    en quoi une nouvelle version de gcc resout le probleme ?

  6. #6
    Membre émérite Avatar de valefor
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    711
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 711
    Par défaut
    Elle résolvait le problème au niveau des atexit ou un truc comme cela... l'ordre dans le quel les fonctions de destruction étaient enregistrées tenait compte du déchargement des bibliothèques :
    Avant tout les destructeurs étaient enregistrés à la fin du programme.
    Après, je ne sais plus comment cela marchait mais il n'y avait plus le problème.

  7. #7
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Bonjour,

    Je trouve vos réponses (Farscape et Emmanuel Deloget) assez mesurées, il me semble que l'on n'a pas vraiment le choix.

    Il me semble que, si l'on veut gérer l'ordre de destruction des singletons, nous sommes "forcés" d'utiliser un
    plutôt qu'un
    ,
    cf la FAQ ici.

    Du coup, ce serait une entorse à la segmentation des responsabilités du code de ne pas gérer la désallocation du pointeur au même endroit que son allocation, c'est à dire dans un objet singleton.

    C'est vrai que si on fait différemment, on n'est pas certain que cela se passe mal : il se peut qu'au cours de la durée de vie du projet, personne n'ajoute jamais aucun autre singleton, ou que les nouveaux singletons ne dépendent jamais des anciens pour leurs construction ou leur destruction.

    Mais cela me semble être du même ordre que pas mal d'autres risques que l'on ne prend pas : il se peut que si l'on n'initialise pas des variables ou si l'on n'alloue pas de la mémoire avant de s'en servir, on n'obtienne jamais de crash ni de fonctionnement aberrant. Et pourtant on ne fait jamais d'entorse à ces règles, même quand on est sur et certain que cela se passera bien.

    Du coup, je me dis qu'il y a quelque chose que j'ai mal compris.
    Pourriez-vous m'éclairer ?
    Merci par avance

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    C'est tout l'avantage de passer par une classe qui contient un pointeur vers l'élément statique

    A partir du moment où ton pointeur est encapsulé, rien ne t'empêche de créer des méthodes qui renverront une référence sur l'instance plutôt qu'un pointeur sur celle-ci...

    En effet, tu peux tout aussi bien bien avoir un code 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
    class Singleton
    {
        public:
            static Singleton& getInstance()
            {
                 if(!instance)
                     instance= new Singleton;
                 return *instance;
            }
            static void freeInstance()
            {
                delete instance;
                instance = NULL;
            }
        private:
            static Singleton *instance;
    };
    que 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
    class Singleton
    {
        public:
            static Singleton* getInstance()
            {
                 if(!instance)
                     instance= new Singleton;
                 return instance;
            }
            static void freeInstance()
            {
                delete instance;
                instance = NULL;
            }
        private:
            static Singleton *instance;
    };
    et, si ton singleton dépend d'un autre singleton, rien ne t'empêcherait même d'écrire un code 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
    25
    26
    27
    28
    29
    class Singleton
    {
        public:
            static Singleton& getInstance()
            {
                 /* Singleton2::getInstance() renvoie également une référence
                  * sur l'instance ;)
                  */
     
                 if(!instance)
                     instance= new Singleton(Singleton2::getInstance());
     
                 /* ou, de manière plus lisible: */
                 if(!instance)
                 {
                     Singleton2 s2=Singleton2::getInstance();
                     instance = new Singelton(s2);
                 }
                 /* renvoi de la référence sur l'instance */
                 return *instance;
            }
            static void freeInstance()
            {
                delete instance;
                instance = NULL;
            }
        private:
            static Singleton *instance;
    };
    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

  9. #9
    Membre éclairé

    Profil pro
    Inscrit en
    Avril 2005
    Messages
    162
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 162
    Par défaut
    Et bien merci beaucoup pour vos réponses constructives.

  10. #10
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Pour ma part, et je sais que je vais en surprendre plus d'un, je ne vois pas d'intérêt à vouloir absolument que le singleton soit détruit à un moment quelconque du programme (y compris une fois que main() a fini de s'exécuter). Nous sommes dans un monde simplifié, ou l'OS prends en charge l'unload do process et termine toutes les ressources allouées par ce process. De fait, la mémoire, les fichiers ouverts, etc sont correctement libéré/fermé/etc à la fin du programme.

    Certes, on peut toujours me répondre "ça fait un resource leak ! ". Et bien non: puisque le singleton est censé être valide à partir du moment ou il est instancié et jusqu'à la fin du programme (c'est à dire, dans un sens, jusqu'à ce que le dernier destructeur de la dernière instance qui a une durée de vie statique ait fini de s'exécuter), quel leak est-ce que je crée si je ne le libère pas en quittant ? Aucun, puisque sitôt après l'exécution du destructeur du singleton, on est censé redonner la main à l'OS pour qu'il fasse le clean up.

    En fait, si on donne à l'utilisateur la possibilité de détruire le singleton quand il le souhaite, on prends le risque de l'autoriser à l'utiliser après qu'il ait été détruit - ce qui est bien plus ennuyeux que de ne pas le détruire au niveau de la maintenance du code.

    J'en entends déjà qui me hurlent "mais un utilisateur lambda ne ferais pas ça!". Certes. C'est possible. Le même utilisateur lambda ne déclarera pas deux instances de la même classe si vous lui dites qu'il n'en a pas le droit. Puisque vous vous substituez à son intelligence en interdisant la création d'une seconde instance de votre classe, pourquoi lui permettre de la détruire après ? Ca n'est pas très consistant
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Servlet]Singleton & cache
    Par lucimast dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 15/12/2004, 16h36
  2. Singleton héritable ?
    Par rolkA dans le forum C++
    Réponses: 10
    Dernier message: 11/12/2004, 16h22
  3. [Débutant] pattern singleton
    Par SirDarken dans le forum Débuter avec Java
    Réponses: 22
    Dernier message: 11/12/2004, 01h55
  4. Mutiple row in singleton select ????? [Important, merci]
    Par SkyDev dans le forum Bases de données
    Réponses: 6
    Dernier message: 20/04/2004, 14h02
  5. [debutant]Singleton
    Par bafman dans le forum Langage SQL
    Réponses: 6
    Dernier message: 13/01/2004, 15h41

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