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 :

Lire un fichier .reg + pb singleton


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Octobre 2011
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut Lire un fichier .reg + pb singleton
    Bonjour,

    J'ai un problème en C++ où je débute. Je suis en période d'essai avec un chef vraiment pas commode ... et je dois réaliser ceci :

    Créer une classe « c_usn_file_registry » qui fournit les 4 méthodes suivantes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static bool c_usn_file_registry::instancier_singleton(nmutility::CString nom_fichier)
    Elle crée un singleton « usn_file_registry », lit le fichier .reg (fichier base de registres) donné en argument, et construit une structure de données interne (basée sur « nmutility::CStdMap ») avec l'ensemble des valeurs contenues dans le fichier.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static c_usn_file_registry* c_usn_file_registry::get_singleton();
    Elle retourne le singleton créé par instancier_singleton.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int c_usn_file_registry::lire_entier(nmutility::CString nom_chemin, nmutility::CString nom_valeur)
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    nmutility::CString c_usn_file_registry::lire_chaine(nmutility::CString nom_chemin, nmutility::CString nom_valeur)
    Ces 2 méthodes retournent l'entier ou la chaîne correspondant à la clé demandée (identifiée par son chemin et son nom).

    Un des mes gros problèmes est que je ne sais pas trop ce qu'est un singleton et donc ce que doivent faire get_singleton et instancier_singleton.

    De plus, il n'y aurait pas une bibliothèque qui saurait faire ça, c'est à dire lire des valeurs dans une fichier .reg ?

    Si quelqu'un pouvait m'aider, son aide serait vraiment la bienvenue ...

    Merci.

    Tapiou.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 369
    Points : 23 623
    Points
    23 623
    Par défaut
    Bonjour,

    En mathématiques, un singleton est un ensemble qui contient un et un seul élément. Exemple : { 0 }. Par extension, en programmation orientée objet, on a appelé « singleton » une classe qui est faite pour n'être instanciée qu'une seule fois (ou, à la limite, un nombre fixe et limité) et qui se réfère ensuite toujours à la même instance.

    http://fr.wikipedia.org/wiki/Singlet..._conception%29

    C'est une approche parfois séduisante mais qui a été décriée par certains.

  3. #3
    Nouveau membre du Club
    Inscrit en
    Octobre 2011
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut
    Merci pour le lien, j'ai la théorie maintenant mais concrètement ?
    Je patauge encore ...

    Tapiou.

  4. #4
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Pour coder un singleton, il y a plusieurs écoles, mais toutes partent d'une variable globale qui contiendra l'instance unique du singleton, et d'une méthode globale pour la récupérer.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class RegReader
    {
       static RegReader* instance;
    public:
       static RegReader* getInstance() { return instance; }
    };
     
    //dans le cpp
    RegReader* RegReader::instance = 0;
    Ca te donne déja l'accès global. Reste ensuite a voir comment tu veux créer ton singleton. Deux options simples :
    Créer une méthode create
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static RegReader* create()
    {
       if(!instance) instance = new RegReader;
       return instance;
    }
    ou alors réécrire getInstance de cette facon afin que getInstance créé l'instance si ce n'est pas fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       static RegReader* getInstance()
    {
       if(!instance) instance=new RegReader;
       return instance;
    }
    Dans tous les cas, il faut coupler ca avec une méthode destroy a appeller quand tu n'as plus besoin du singleton
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       static void destroyInstance()
    {
       if(instance) delete instance;
       instance=0;
    }
    Dans tous les cas, constructeur et destructeur privé afin de prévenir une création ou une destruction autrement que par les méthodes fournies

  5. #5
    Nouveau membre du Club
    Inscrit en
    Octobre 2011
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut
    Merci Rewpparo !

    Tes explications vont bien m'aider

    Mais bon j'ai encore du travail pour résoudre l'ensemble du problème, vu que je débute en C++ et que j'avance comme une tortue.

    Donc s'il y a une bonne âme qui a des suggestions à me faire, surtout qu'elle n'hésite pas !

    Tapiou.

  6. #6
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Un truc :
    Citation Envoyé par tapiou Voir le message
    De plus, il n'y aurait pas une bibliothèque qui saurait faire ça, c'est à dire lire des valeurs dans une fichier .reg ?
    je pense qu'il te faudra le parser à la main. Utilises fstream pour faire ca.

  7. #7
    Nouveau membre du Club
    Inscrit en
    Octobre 2011
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut
    Merci pour l'info, je vais regarder.

    Tapiou.

  8. #8
    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,
    Citation Envoyé par Rewpparo Voir le message
    Pour coder un singleton, il y a plusieurs écoles, mais toutes partent d'une variable globale qui contiendra l'instance unique du singleton, et d'une méthode globale pour la récupérer.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class RegReader
    {
       static RegReader* instance;
    public:
       static RegReader* getInstance() { return instance; }
    };
     
    //dans le cpp
    RegReader* RegReader::instance = 0;
    Ca te donne déja l'accès global. Reste ensuite a voir comment tu veux créer ton singleton. Deux options simples :
    Créer une méthode create
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static RegReader* create()
    {
       if(!instance) instance = new RegReader;
       return instance;
    }
    ou alors réécrire getInstance de cette facon afin que getInstance créé l'instance si ce n'est pas fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       static RegReader* getInstance()
    {
       if(!instance) instance=new RegReader;
       return instance;
    }
    Dans tous les cas, il faut coupler ca avec une méthode destroy a appeller quand tu n'as plus besoin du singleton
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       static void destroyInstance()
    {
       if(instance) delete instance;
       instance=0;
    }
    Dans tous les cas, constructeur et destructeur privé afin de prévenir une création ou une destruction autrement que par les méthodes fournies
    Une autre solution consiste à utiliser une variable statique directement dans getInstance:
    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
    class Reader
    {
        public:
            static Reader & getInstance()
            {
                static Reader r;
                return r;
            }
            /* !!!C++11 ony !!!
             * interdire la copie et l'affectation (il faut d'ailleurs veiller à le faire
             * aussi dans la version de Rewpparo ;) )
             */
              Reader(Reader const &) = delete;
              Reader & operator = ( Reader const &) = delete;
     
        /* les fonctions qui vont bien */
        private:
            /* avant C++11 :
             * interdire la copie et l'affectation
             */
           Reader(Reader const &); // déclaré, non implémenté (pour éviter
                                        // que le compilateur ne fournisse la version publique)
           Reader & operator= (Reader const &); // déclaré, non implémenté (pour éviter
                                        // que le compilateur ne fournisse la version publique)
            Reader(); // à implémenter ;)
            ~Reader(); // à implémenter ;)
    }
    Cela permet d'éviter le recours à un pointeur, et donc de garder une syntaxe objet

    Ceci dit
    On ne le répétera jamais assez, mais les singletons et les variables statiques, c'est mal!!!

    La raison principale est qu'une variable statique n'est finalement qu'une variable globale qui se cache bien, mais elle présente exactement les mêmes problèmes en termes de réentrance et de pureté des fonctions!!!

    Le tout, sans oublier que, du fait de sa disponibilité dans l'ensemble du code, l'utilisateur peut etre tenté d'accéder à cette variable globale (ou à ce singleton) depuis des endroits de code auxquels il ne devrait pas pouvoir y accéder, avec tous les risques que cela comporte en terme de dépendances ou de références circulaires!!!

    Et si tu le souhaites, on peut aussi parler des problèmes relatifs à la gestion de threads et des mécanismes nécessaires pour arriver à gérer le singleton de manière thread safe

    Le meilleur moyen de garantir qu'il n'y aura jamais qu'une et une seule instance d'un type donné est encore de déclarer cette variable dans une partie du code que l'on sait n'être utilisée qu'une seule fois (par exemple, au niveau de la classe principale de l'application ) et de veiller à ne transmettre cette variable (sous forme de référence, éventuellement constante) qu'aux fonctions qui en ont impérativement besoin

    Je me suis récemment retrouvé face à un code où il n'y avait pas un singleton, mais carrément plusieurs, avec un singleton qui regroupait, ou peu s'en faut, l'ensemble des fonctionnalités des autres...

    Le problème, quand j'ai voulu apporter une modification due à l'évolution du business, c'est que je me suis aperçu que les singleton "secondaires" (ou du moins celui sur lequel je devais travailler) faisaient régulièrement appel à ce singleton "général"

    Je ne te raconte pas les soucis que cela m'a occasionné pour arriver à faire ce que l'on m'avait demandé
    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
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 369
    Points : 23 623
    Points
    23 623
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je me suis récemment retrouvé face à un code où il n'y avait pas un singleton, mais carrément plusieurs, avec un singleton qui regroupait, ou peu s'en faut, l'ensemble des fonctionnalités des autres...

    Le problème, quand j'ai voulu apporter une modification due à l'évolution du business, c'est que je me suis aperçu que les singleton "secondaires" (ou du moins celui sur lequel je devais travailler) faisaient régulièrement appel à ce singleton "général"

    Je ne te raconte pas les soucis que cela m'a occasionné pour arriver à faire ce que l'on m'avait demandé
    Arrivé à ce point, je pense qu'on peut légitimement se demander en quoi ça reste de la programmation objet. :-) De bonnes vieilles fonctions impératives auraient largement rempli leur mission.

  10. #10
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
            static Reader & getInstance()
            {
                static Reader r;
                return r;
            }
    Je ne comprend pas la syntaxe, pour moi une static c'est dans une classe. La ca fait un peu variable locale static (oxymore). C'est comme déclarer une variable static, mais qu'on ne peut utiliser que dans la méthode ?
    Ca demande quand même une définition dans le cpp ?

    Citation Envoyé par koala01 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            /* !!!C++11 ony !!!
             * interdire la copie et l'affectation (il faut d'ailleurs veiller à le faire
             * aussi dans la version de Rewpparo ;) )
             */
    Citation Envoyé par Rewpparo Voir le message
    Dans tous les cas, constructeur et destructeur privé afin de prévenir une création ou une destruction autrement que par les méthodes fournies
    J'aurais du le mettre plus en avant, car c'est vrai que c'est une partie intégrante du pattern.

    Ceci dit
    On ne le répétera jamais assez, mais les singletons et les variables statiques, c'est mal!!!
    +1, mais en l'occurence c'est son patron pas commode qui a imposé le pattern. Et pour espèce de base de registre, je trouve que c'est le seul cas où ca se justifie. Le seul singleton de mon projet est quelque chose du style.

    Et j'ajouterais sur les variables globales que pour moi les seules acceptables sont privées, et en pensant bien l'interface.

  11. #11
    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 Obsidian Voir le message
    Arrivé à ce point, je pense qu'on peut légitimement se demander en quoi ça reste de la programmation objet. :-) De bonnes vieilles fonctions impératives auraient largement rempli leur mission.
    Oui, je sais...

    Mais bon, je te rassure, je ne suis pas du tout responsable de cet imbroglio, je n'ai fait que le subir
    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

  12. #12
    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 Rewpparo Voir le message
    Je ne comprend pas la syntaxe, pour moi une static c'est dans une classe. La ca fait un peu variable locale static (oxymore). C'est comme déclarer une variable static, mais qu'on ne peut utiliser que dans la méthode ?
    Ca demande quand même une définition dans le cpp ?
    Non, pas du tout...

    On profite du fait que la fonction continue d'exister (du fait de sa déclaration comme static) en dehors de la fonction, et qu'elle n'est pas recréée à chaque fois que la fonction est appelée, tout simplement

    La raison qui fait qu'une variable membre statique doit etre définie dans le *.cpp est, tout simplement, due au fait qu'elle doit être construite avant le premier appel au constructeur de la classe dans laquelle elle se trouve, étant donné qu'une variable statique est totalement indépendante de toute instance de la classe.

    Dans le cadre d'une variable de fonction, il en va tout autrement : elle peut parfaitement n'être créée qu'au premier appel de la fonction (qui, elle doit, pour le pattern singleton du moins, etre statique pour ne pas dépendre d'une instance de la classe) vu qu'elle ne sera de toutes manières pas utilisée... avant le premier appel à la fonction
    J'aurais du le mettre plus en avant, car c'est vrai que c'est une partie intégrante du pattern.
    C'est pour cela que je l'ai mis en évidence, en indiquant les deux solutions

    Mais je ne doute absolument pas que l'oubli n'est du qu'à une distraction passagère ou à une quelconque activité t'ayant incité à terminer ta réponse au plus vite

    +1, mais en l'occurence c'est son patron pas commode qui a imposé le pattern.
    Je sais bien, mais bon, ce n'est pas une raison pour ne pas faire le rappel, et, qui sait, inciter tapiou à dire à son patron que "CEYMAL"
    Et pour espèce de base de registre, je trouve que c'est le seul cas où ca se justifie. Le seul singleton de mon projet est quelque chose du style.
    Je dirais plutot : justement !!! la base de registre, est, typiquement, lue une fois à l'initialisation de l'application et, éventuellement, lue à la sortie de celle-ci...

    Et une grosse partie des informations qu'elle contient n'ont, en définitive, qu'une portée très limitée dans le temps (ex : la vérification de la license qui ne sera typiquement utilisée qu'au lancement de l'application)...

    Il me semble dommage de se trimbaler l'ensemble des informations chaque fois que l'on souhaite savoir si le texte doit etre écrit en vert fluo ou en brun caca doigt et, surtout, de se trimbaler en plus tout le système de lecture et d'écriture que cela sous tend

    Car, plus ces informations vont voyager au travers de l'application, plus on est susceptible d'aller y chipoter, de manière autorisée ou non

    N'hésitons pas à créer une classe Reader et une classe Writer, mais utilisons les intelligemment : Reader dans le constructeur pour aller chercher les infos (et les placer aux endroits qui vont bien) et Writer dans le destructeur pour aller chercher les infos où elles se trouvent et les réécrire dans la base de registre
    Et j'ajouterais sur les variables globales que pour moi les seules acceptables sont privées, et en pensant bien l'interface.
    ... ou constantes, si elles sont publique
    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

  13. #13
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Non, pas du tout...

    On profite du fait que la fonction continue d'exister (du fait de sa déclaration comme static) en dehors de la fonction, et qu'elle n'est pas recréée à chaque fois que la fonction est appelée, tout simplement

    La raison qui fait qu'une variable membre statique doit etre définie dans le *.cpp est, tout simplement, due au fait qu'elle doit être construite avant le premier appel au constructeur de la classe dans laquelle elle se trouve, étant donné qu'une variable statique est totalement indépendante de toute instance de la classe.

    Dans le cadre d'une variable de fonction, il en va tout autrement : elle peut parfaitement n'être créée qu'au premier appel de la fonction (qui, elle doit, pour le pattern singleton du moins, etre statique pour ne pas dépendre d'une instance de la classe) vu qu'elle ne sera de toutes manières pas utilisée... avant le premier appel à la fonction
    C'est pour cela que je l'ai mis en évidence, en indiquant les deux solutions
    C'est intéressant, je connaissais pas. Comment ca marche si le singleton est défini dans des libs ? J'ai eu des problèmes il y a longtemps avec des variables static qui n'étaient pas synchrones entre une lib et le programme principal, problèmes que d'ailleurs je n'avais pas vraiment compris et qui m'ont amené à considérer avec encore plus de méfiance toute variable static, surtout les singletons. Ça change quelque chose d'utiliser static comme ca ?

    Citation Envoyé par koala01 Voir le message
    Je dirais plutot : justement !!! la base de registre, est, typiquement, lue une fois à l'initialisation de l'application et, éventuellement, lue à la sortie de celle-ci...

    Et une grosse partie des informations qu'elle contient n'ont, en définitive, qu'une portée très limitée dans le temps (ex : la vérification de la license qui ne sera typiquement utilisée qu'au lancement de l'application)...

    Il me semble dommage de se trimbaler l'ensemble des informations chaque fois que l'on souhaite savoir si le texte doit etre écrit en vert fluo ou en brun caca doigt et, surtout, de se trimbaler en plus tout le système de lecture et d'écriture que cela sous tend

    Car, plus ces informations vont voyager au travers de l'application, plus on est susceptible d'aller y chipoter, de manière autorisée ou non
    En l'occurrence, je me sert de ca pour un jeu vidéo, pour enregistrer les paramètres comme les paramètres de la fenêtre, les touches, etc.. Le singleton centralise les infos de plusieurs sources (argc argv, fichier de conf, IHM de config) et les met à disposition de ceux qui en ont besoin.

    Les touches par exemple, j'ai besoin d'en savoir la configuration a chaque fois que je lance une partie pour recréer les binds, ou si le joueur monte dans un véhicule et change de manière de contrôler le jeu.

    La fenêtre, j'en ai besoin que quand ca change, mais ca peut changer à n'importe quel moment, y compris pendant la partie.

    J'ai donc besoin des infos un peu tout le temps. Je pourrais me contenter de faire une classe qui facilite l'accès au fichier de conf, mais je ne ferais que déplacer le problème, et ca ne me permettrais pas de mixer facilement le fichier de conf et les arguments de ligne de commande.

  14. #14
    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 Rewpparo Voir le message
    En l'occurrence, je me sert de ca pour un jeu vidéo, pour enregistrer les paramètres comme les paramètres de la fenêtre, les touches, etc.. Le singleton centralise les infos de plusieurs sources (argc argv, fichier de conf, IHM de config) et les met à disposition de ceux qui en ont besoin.

    Les touches par exemple, j'ai besoin d'en savoir la configuration a chaque fois que je lance une partie pour recréer les binds, ou si le joueur monte dans un véhicule et change de manière de contrôler le jeu.

    La fenêtre, j'en ai besoin que quand ca change, mais ca peut changer à n'importe quel moment, y compris pendant la partie.

    J'ai donc besoin des infos un peu tout le temps. Je pourrais me contenter de faire une classe qui facilite l'accès au fichier de conf, mais je ne ferais que déplacer le problème, et ca ne me permettrais pas de mixer facilement le fichier de conf et les arguments de ligne de commande.
    Tu as besoin de tout pendant toute la durée de ton application, mais tu n'as (ou, du moins, tu devrais n'avoir) besoin d'informations particulières que sur des portions de code bien définies...

    Pour reprendre tes exemples :

    Tu vas, effectivement, avoir besoin de la lire la configuration des touches au chargement, mais elles ne seront manipulées finalement qu'à deux endroits : dans le gestionnaire d'événement pour déterminer quelle action est entreprise sur l'appui de quelle touche et, éventuellement, au niveau du panneau de configuration, qui devra de toutes manière disposer du système d'événement pour y faire les mises à jour.

    Il n'y a que le gestionnaire graphique (et encore une fois, le panneau de configuration) qui ait réellement besoin des informations de fenêtre, meme si elles sont lues en début de partie, et, encore une fois, le panneau de configuration devra, de toutes manières, s'adresser au gestionnaire graphique pour lui faire prendre les nouveaux réglages en comptes.

    On peut continuer comme cela pour tout ce qu'on peut imaginer : les informations relatives au niveau de difficulté n'intéressent que le moteur de jeu et l'intelligence artificielle (et, décidément, toujours le panneau de configuration ), la gestion des sauvegarde de données n'intéresse éventuellement que la partie propre à la gestion de l'inventaire et à la gestion de la position dans le jeu dans le moteur de jeu, et ainsi de suite

    Par contre, tu n'en auras rien à foutre d'avoir la taille de la fenêtre au niveau du moteur d'intelligence artificielle ou quand il s'agira d'évaluer le niveau de difficulté du jeu

    Etant entendu que tu n'auras de toute manière qu'un moteur de jeu, un moteur graphique, un gestionnaire d'événement etc , pourquoi ne pas faire en sorte que les informations qui les intéressent se trouvent dans ces différents modules (quitte à créer une classe dont la responsabilité serait à chaque fois de maintenir les informations à jour )

    Tu auras, bien sur, des dépendances entre ces différents modules, car certains d'entre eux devront, de toutes manières, transmettre des informations à d'autres, mais le fait de "dispatcher" les informations au niveau du "module" t'éviterait d'avoir des dépendances partant "dans tous les sens" 'uniquement" parce que tu as été "assez bête" que pour regrouper les informations propres au moteur de rendu et celles propres à la gestion de la difficulté au sein d'une classe qui chapeaute le tout, mais qui a, en retour, une dépendance forte envers tout

    Le tout, sans oublier le fait que, en mettant au point une stratégie de séparation de l'information assez fine, tu gardera un bien meilleur contrôle sur le "qui fait quoi" avec ces données, t'évitant ainsi que l'appuis malencontreux sur une touche ne te fasse passe en 800/600 alors que ton pc est configuré en 1920 par dieu sait combien (et autres joyeusetés du genre, évidemment )

    Après, il reste bien sur le cas particulier du panneau de configuration qui doit avoir accès à la quasi totalité des endroits où les informations sont maintenues...

    Mais, comme il doit, de toutes manières, avoir accès à ces différents modules pour leur indiquer (le cas échéant) qu'une partie de la configuration a changé et qu'ils doivent en tenir compte, même quand toutes les infos sont regroupées au niveau d'un singleton, il n'y a, a priori pas d'inquiétudes à avoir
    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

  15. #15
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Etant entendu que tu n'auras de toute manière qu'un moteur de jeu, un moteur graphique, un gestionnaire d'événement etc , pourquoi ne pas faire en sorte que les informations qui les intéressent se trouvent dans ces différents modules (quitte à créer une classe dont la responsabilité serait à chaque fois de maintenir les informations à jour )
    Parce que ces informations ont des points de centralisation forts : les paramètres de la ligne de commande et le fichier de configuration. Je pourrais les dispatcher entre les différents modules au démarrage, et les collecter quand il s'agit d'enregistrer le fichier de conf. Mais il faudra que je revoie le code de collecte/dispatch à chaque fois que j'ajoute un nouveau paramètre pour l'envoyer au bon endroit ou le récupérer au bon endroit. La chaque système récupère les paramètres dont il a besoin, s'il n'est pas présent il définit lui même la valeur qu'il veut, et elle sera enregistrée pour la fois suivante.

    Citation Envoyé par koala01 Voir le message
    Après, il reste bien sur le cas particulier du panneau de configuration qui doit avoir accès à la quasi totalité des endroits où les informations sont maintenues...

    Mais, comme il doit, de toutes manières, avoir accès à ces différents modules pour leur indiquer (le cas échéant) qu'une partie de la configuration a changé et qu'ils doivent en tenir compte, même quand toutes les infos sont regroupées au niveau d'un singleton, il n'y a, a priori pas d'inquiétudes à avoir
    Justement, chez moi le panneau de configuration ne fait que signifier les nouveaux paramètres au singleton, qui lui va envoyer des events aux différents systèmes pour leur signifier les changements. Ça évite que le panneau de configuration ne touche à tout justement, car là aussi tu as une dépendance forte, et à un endroit beaucoup plus sensible. Certes mon singleton est une dépendance forte, mais au moins lui je suis sur qu'il ne dépend de personne, donc pas de dépendances cycliques ou autres.
    C'est même principalement pour résoudre cette dépendance que je me suis résolu a utiliser un singleton.


    Citation Envoyé par koala01 Voir le message
    Le tout, sans oublier le fait que, en mettant au point une stratégie de séparation de l'information assez fine, tu gardera un bien meilleur contrôle sur le "qui fait quoi" avec ces données, t'évitant ainsi que l'appuis malencontreux sur une touche ne te fasse passe en 800/600 alors que ton pc est configuré en 1920 par dieu sait combien (et autres joyeusetés du genre, évidemment )
    C'est en effet la seule faiblesse de mon système, le manque de gestion de permissions. Mais c'est simple a débugger, il suffit de regarder le fichier de conf pour voir le paramètre qui merde, et chercher le bout de code qui touche à cette clé. Les conventions d'écriture dans les clés permettent de limiter le risque d'erreur en séparant bien tout en sections (video, IA, physique..). Je pourrais même créer des interfaces qui limitent la capacité d'édition à telle ou telle section si je rencontre des problèmes.

  16. #16
    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 Rewpparo Voir le message
    Parce que ces informations ont des points de centralisation forts : les paramètres de la ligne de commande et le fichier de configuration. Je pourrais les dispatcher entre les différents modules au démarrage, et les collecter quand il s'agit d'enregistrer le fichier de conf. Mais il faudra que je revoie le code de collecte/dispatch à chaque fois que j'ajoute un nouveau paramètre pour l'envoyer au bon endroit ou le récupérer au bon endroit.
    Je présumes que tu as déjà pris soin d'enregistrer ta conf "par lot", dans le sens ou ta fonction write (ou read, selon le sens de travail ) ressemble sans doute à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void singleton::write()
    {
        saveWindowConfig();
        saveKeyConfig();
        saveDifficultyConfig();
        /* ...*/
    }
    chaque fonction se chargeant de sauvegarder (ou de lire, en core une fois) le lot d'informations qui l'intéresse, chaque fonction appelant d'autres fonctions traitant des lots plus particuliers ...

    J'espère en tout cas que tu n'a pas tapé tes options de configuration "au petit bonheur la chance" en fonction de tes besoins, car tu finira par avoir vraiment énormément de mal à t'y retrouver

    Si tel est effectivement le cas, un simple "Reader" en début d'application et un Writer en fin d'application permettent (qui peuvent d'ailleurs etre regroupés en "Serializer, avec les fonctions read et write ), suffisent très amplement à envoyer les lots d'informations vers "qui de droit" et à les récupérer, en ne devant au pire rajouter qu'une instruction chaque fois que tu rajoutes une option de configuration
    La chaque système récupère les paramètres dont il a besoin, s'il n'est pas présent il définit lui même la valeur qu'il veut, et elle sera enregistrée pour la fois suivante.
    Qu'est ce qui t'empêche de faire que ce comportement ait lieu au niveau du module, juste après réception des lots d'information

    Le problème que j'exposais la tantot pour indiquer qu'il fallait vraiment éviter les singletons, il est survenu pour une raison bien simple : le singleton général avait été nommé "PropertyManager"...

    Un nom bateau s'il en est qui permet de regrouper tout ce qui ressemble de près ou de loin à une propriété (et dieu sait, s'il existe, que l'on peut trouver des propriétés partout )

    Au fil des cinq ans de développement, c'est devenu une espèce de monstre polymorphe dont on s'étonnerait presque qu'il ne fasse pas le café

    (Il faut dire, pour etre précis, qu'il enregistre en plus ses données dans trois fichiers totalement différents )

    Cela fait maintenant un an que l'on se rend effectivement compte que ce truc devient impossible à gérer sous cette forme et que l'on essaye de dispatcher les différentes responsabilités dans différents gestionnaires plus spécialisés, le tout (c'est quand meme préférable pour une application qui est en prod ) en évitant de tout casser...

    (Et, pour faire taire les mauvaises langues, c'est à peu près lors de mon arrivée sur le projet que l'on a décidé de lancer de "refactoring" progressif, meme si je n'en suis pas l'instigateur, je ne suis pas responsable de la dérive )

    Si je te raconte cela, c'est pour te dire qu'il s'agit d'une expérience vécue, et d'une situation que je subis encore au jour le jour, et non d'un simple exercice de style de "belle programmation" .

    Ce que j'essaye de t'expliquer c'est que, que tu travailles en solo pour ton propre plaisir ou en équipe à titre professionnel, la seule présence du singleton pour gérer la configuration, surtout s'il est nommé PropertyManager ou ConfigManager t'ouvre une voie royale et t'emmène déjà dessus pour en arriver à un mastodonte effrayant dont tout le monde dit qu'il faut revoir la technique mais dont personne n'ose vraiment s'y coller, de peur de "tout casser"...

    Si tu as encore l'occasion de revenir en arrière et de couper la tête à hydre avant qu'elle ne devienne monstrueuse, crois moi, il est surement plus que temps de t'y atteler, car si tu décides de t'y mettre quand tu te rendras effectivement compte que cela devient ingérable, tu vas très certainement t'y casser les dents

    Justement, chez moi le panneau de configuration ne fait que signifier les nouveaux paramètres au singleton, qui lui va envoyer des events aux différents systèmes pour leur signifier les changements. Ça évite que le panneau de configuration ne touche à tout justement, car là aussi tu as une dépendance forte, et à un endroit beaucoup plus sensible. Certes mon singleton est une dépendance forte, mais au moins lui je suis sur qu'il ne dépend de personne, donc pas de dépendances cycliques ou autres.
    C'est même principalement pour résoudre cette dépendance que je me suis résolu a utiliser un singleton.
    Le gros problème, c'est que le singleton devient le "point de rencontre" de tous tes modules, et que chaque module dépend explicitement de ton singleton, en plus de toutes les dépendances plus "logiques"...

    Il suffit donc que tu rajoutes une fonction pour gérer un nouvel aspect de ta fenêtre pour que tu te trouves face à l'obligation de recompiler l'ensemble des modules (que ce soit en tout ou en partie) alors que tu aurais très bien pu n'avoir à recompiler que le module graphique (pour suivre mon exemple ), et encore... meme pas forcément l'ensemble du module graphique
    C'est en effet la seule faiblesse de mon système, le manque de gestion de permissions. Mais c'est simple a débugger, il suffit de regarder le fichier de conf pour voir le paramètre qui merde, et chercher le bout de code qui touche à cette clé. Les conventions d'écriture dans les clés permettent de limiter le risque d'erreur en séparant bien tout en sections (video, IA, physique..). Je pourrais même créer des interfaces qui limitent la capacité d'édition à telle ou telle section si je rencontre des problèmes.
    Je sais bien qu'aucun problème n'est insurmontable, et qu'il y a très facilement moyen de retrouver l'endroit ou un "imbécile touche à ce qu'il ne doit pas"

    Mais, si, d'un autre coté, au prix de relativement peu d'efforts (enfin, à moins que tu ne développe ton truc depuis cinq ans ), il y a moyen, non seulement de faire en sorte d'éviter ce genre de problème, mais aussi d'éviter le cout d'un refactoring d'ici "quelques années", tu ne crois pas que ca vaut franchement la peine de s'accorder le temps nécessaire à un changement d'optique
    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

  17. #17
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je présumes que tu as déjà pris soin d'enregistrer ta conf "par lot", dans le sens ou ta fonction write (ou read, selon le sens de travail ) ressemble sans doute à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void singleton::write()
    {
        saveWindowConfig();
        saveKeyConfig();
        saveDifficultyConfig();
        /* ...*/
    }
    chaque fonction se chargeant de sauvegarder (ou de lire, en core une fois) le lot d'informations qui l'intéresse, chaque fonction appelant d'autres fonctions traitant des lots plus particuliers ...
    Citation Envoyé par koala01 Voir le message
    Il suffit donc que tu rajoutes une fonction pour gérer un nouvel aspect de ta fenêtre pour que tu te trouves face à l'obligation de recompiler l'ensemble des modules (que ce soit en tout ou en partie) alors que tu aurais très bien pu n'avoir à recompiler que le module graphique (pour suivre mon exemple ), et encore... meme pas forcément l'ensemble du module graphique
    Je sais bien qu'aucun problème n'est insurmontable, et qu'il y a très facilement moyen de retrouver l'endroit ou un "imbécile touche à ce qu'il ne doit pas"
    Non justement, je n'ai rien fait de tel, c'est pas du tout l'optique. Le but est de faire quelque chose de complètement générique, justement afin de ne pas avoir tout retoucher des qu'on invente une nouvelle section.


    Citation Envoyé par koala01 Voir le message
    Au fil des cinq ans de développement, c'est devenu une espèce de monstre polymorphe dont on s'étonnerait presque qu'il ne fasse pas le café
    J'y ai pensé. La partie config du jeu sera générée à la volée en fonction des clés dans le singleton. Donc on ne met dedans que les propriétés qu'on veut voir exposées à l'utilisateur final. Le reste se fait avec des defines ou autres (pour les tests, les "on verra plus tard" etc).
    De plus, la plupart des unit tests sont faits sans que le singleton ne soit créé, donc les classes doivent pouvoir se démerder sans.


    Citation Envoyé par koala01 Voir le message
    Le gros problème, c'est que le singleton devient le "point de rencontre" de tous tes modules, et que chaque module dépend explicitement de ton singleton, en plus de toutes les dépendances plus "logiques"...
    Avec ton design, j'aurais le même goulet d'étranglement au niveau du panneau de config, a part que le panneau de config a autrement plus de dépendances (graphique, input, gamestate) que mon singleton qui gère son truc dans son coin et envoie des events asynchrones.

    Citation Envoyé par koala01 Voir le message
    Mais, si, d'un autre coté, au prix de relativement peu d'efforts (enfin, à moins que tu ne développe ton truc depuis cinq ans ), il y a moyen, non seulement de faire en sorte d'éviter ce genre de problème, mais aussi d'éviter le cout d'un refactoring d'ici "quelques années", tu ne crois pas que ca vaut franchement la peine de s'accorder le temps nécessaire à un changement d'optique
    Tout à fait, c'est pourquoi ton avis m'intéresse beaucoup. J'espère que tu ne vois pas dans cette discussion une simple querelle idéologique, c'est juste ma façon de raisonner, j'aime pas suivre les conseils juste parce qu'on me les donne, j'aime comprendre les tenants et aboutissants. S'il y a des problèmes que j'ai pas anticipé, je suis toujours preneur.
    Mais on a tous le même travers : si on est confronté à une grosse erreur de design qui nous pose de gros problèmes et nous fait perdre plein de temps, on a tendance à refuser tout ce qui s'en approche. J'ai d'autres bons exemples (fragmentation mémoire par exemple). C'est pourquoi j'essaie de comprendre exactement les problèmes que tu as rencontré afin de vérifier si j'ai bien tout anticipé.

  18. #18
    Nouveau membre du Club
    Inscrit en
    Octobre 2011
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut
    Rewpparo et koala01,

    Vous avez eu une sacrée conversation grâce à moi finalement ...
    Et je me dis que le jour où je pourrais comprendre tout ce que vous êtes raconté, çà sera le pied mais en attendant je galère...

    Alors je me permets de demander encore de l'aide parce que pour vous çà a l'air tellement facile et que pour moi, c'est tellement compliqué.

    Est-ce que vous pourriez m'aider à coder la méthode
    static bool c_usn_file_registry::instancier_singleton(nmutility::CString nom_fichier)
    qui crée le singleton « usn_file_registry », lit le fichier .reg (fichier base de registres) donné en argument, et construit une structure de données interne (basée sur « CStdMap ») avec l'ensemble des valeurs contenues dans le fichier.

    Pour l'aspect singleton, maintenant j'ai compris, pour la lecture du fichier je devrais m'en sortir aussi mais alors pour mettre les valeurs lues dans la structure CStdMap (qui se trouve dans le fichier que j'ai joint) alors là dur !

    Merci.

    Tapiou.
    Fichiers attachés Fichiers attachés

  19. #19
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Vu comment on a highjacké ton sujet, on va finir de t'aider
    Alors chaque dans ton fichier .reg tu dois avoir des ensemble clé/valeur sous forme de string. D'abord il te faut un CStdMap<string, string> quelque part dans ta classe, appelons le map. Pour chaque couple que tu récupère dans le .reg, tu as juste a faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     map.insert(clé, valeur)
    C'est en fait juste un wrapper pour std::map il me semble, ca marche plus ou moins pareil.
    Ca répond à ta question ?

  20. #20
    Nouveau membre du Club
    Inscrit en
    Octobre 2011
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut
    Merci Rewpparo.

    Je ne comprends pas bien.
    J'ai joint un exemple de fichier .reg (que j'ai renommé en .txt sinon je ne pouvais pas le joindre).

    Dans ma tête, j'imaginais que la structure à construire représentait dans le cas de ce fichier, 12 items avec à chaque fois 3 valeurs associées :

    Ce qui donnerait pour le premier item :
    - La chaîne de caractères de type HKEY
    Exple : [HKEY_LOCAL_MACHINE\SOFTWARE\Entreprise\UXT\MINMGR]

    - La chaîne représentant le flag
    Exple : "TRACE_DIRECTORY"

    - La chaîne représentant la valeur
    Exple : "JOKER_TARGET\\Data\\Logs\\Traces\\Command"

    et pour le deuxième item :
    [HKEY_LOCAL_MACHINE\SOFTWARE\Entreprise\UXT\MINMGR]
    "DragAndDrop"
    dword:00000000

    et ainsi de suite pour les 10 autres items.

    Et donc que ce que tu as appelé map serait un CStdMap<string, string, string> avec 3 fois string donc.
    Mais je vois bien que ce n'est pas possible et que c'est toi qui a raison, mais alors je ne comprends où est stockée l'info du type " [HKEY_LOCAL_MACHINE\SOFTWARE\Entreprise\UXT\MINMGR]"

    Pour toi, dans un map.insert(clé, valeur), clé aurait par exemple pour valeur "TRACE_DIRECTORY" et valeur aurait pour valeur "JOKER_TARGET\\Data\\Logs\\Traces\\Command" ?

    Mais alors où est traitée l'information "[HKEY_LOCAL_MACHINE\SOFTWARE\Entreprise\UXT\MINMGR]" ?

    Gloups ...

    Merci.

    Tapiou.
    Fichiers attachés Fichiers attachés

Discussions similaires

  1. [Servlet][EJB]lire un fichier à partir de mon bean
    Par kimausoleil dans le forum Servlets/JSP
    Réponses: 3
    Dernier message: 13/02/2004, 14h26
  2. [MFC] lire un fichier en int
    Par Kevgeii dans le forum MFC
    Réponses: 3
    Dernier message: 23/01/2004, 09h32
  3. Réponses: 5
    Dernier message: 11/01/2004, 20h17
  4. Lire un fichier de 50 gb
    Par Maryves dans le forum MFC
    Réponses: 2
    Dernier message: 08/01/2004, 14h08
  5. Lire le fichier du port série
    Par saibe dans le forum Linux
    Réponses: 7
    Dernier message: 09/04/2003, 09h29

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