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 :

[Conception] Structures partagées par des objets


Sujet :

C++

  1. #1
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut [Conception] Structures partagées par des objets
    Bonjour

    Un petit topic de conception comme on les aime. J'ai besoin de créer des objets qui accèderont à une map pour mettre en correspondance une chaîne avec la valeur d'un enum. Cette map est commune à tous les objets.

    Ma technique habituelle consiste à créer une factory qui portera cette map et en donnera une référence aux objets créés. Cela permet d'éviter de trimbaler un singleton et éventuellement de moduler la map pour créer des "groupes d'objets" au comportement différent.Mais il y a un gros défaut: c'est que la map créée par la factory voit sont cycle de vie lié à celui des objets créés, et ceux ci ne fonctionnent plus si elle est détruite (à la destruction de la factory par exemple).

    Une solution serait de dire que la propriété de la map est partagée entre les objets, et donc, je n'ai qu'à la mettre dans un share_ptr. Là, on en arrive aux limites de mon contexte:
    - J'ai pas shared_ptr (pas de boost ni C++11, sinon je me ferais plez avec des hash map compile time à base de const_expr)
    - Je voudrais que le code reste au plus simple car mon besoin est relativement simple, donc pas question de réimplémenter un shared_ptr maison pour ça ni de faire un truc compliqué.

    Comment feriez-vous ?
    Find me on github

  2. #2
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    ça vaut ce que ça vaut, mais pour le besoin, je laisserai tomber l'idée d'une factory, et je ferai juste un namespace avec ma map et quelques méthode spécifiques à mes besoins.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    namespace ma_map
    {
       std::map<string, monTypeEnum> m_map;
     
       void ajouter(string key, monTypeEnum value);
     
       //etc
    }
    ou une classe statique...
    c'est vrai que pour un truc aussi simple que "je veux une map commune à tous mes objets pour mapper une string avec un enum", il y a plus simple.
    Un exemple d'utilisation :

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
    #ifndef PRESIDENT_HPP
    #define PRESIDENT_HPP
     
    //headers standards
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <random>
    #include <ctime>
     
    //headers personnels
    #include "Carte.hpp"
    #include "Constantes.hpp"
    #include "Joueur.hpp"
     
    namespace Jeu
    {
        //variables
        std::vector<Carte> Paquet;
        std::vector<Carte> Defausse;
     
        //Melanger les cartes
        void Melanger()
        {
            //ne fonctionne pas... à analyser
            //std::random_device rd;
            //std::default_random_engine re(rd());
            srand(time(NULL));
            std::random_shuffle(Paquet.begin(), Paquet.end());
        }   
     
        //initialiser le jeu a un jeu de 32 cartes
        void Init_32_cartes()
        {
            if(!Paquet.empty()) Paquet.clear();
     
            for(auto couleur = Carte::Couleur::Trefle; couleur < Carte::Couleur::Sans; couleur++){
                for(Carte::Valeur valeur = Carte::Valeur::Sept; valeur < Carte::Valeur::Joker; valeur++)
                    Paquet.push_back(Carte(valeur, couleur));
            }
        }
     
        //initialiser le jeu a un jeu de 54 cartes
        void Init_54_cartes()
        {
            if(!Paquet.empty()) Paquet.clear();
     
            for(auto couleur = Carte::Couleur::Trefle; couleur < Carte::Couleur::Sans; couleur++){
                for(auto valeur = Carte::Valeur::Trois; valeur < Carte::Valeur::Joker; valeur++)
                    Paquet.push_back(Carte(valeur, couleur));
            }
     
            /* Ajout des jokers */
            Carte joker(Carte::Valeur::Joker, Carte::Couleur::Sans);
            Paquet.push_back(joker);
            Paquet.push_back(joker);
     
        }
     
        //Distribuer les cartes a tous les joueurs presents
        void Distribuer()
        {
            for (auto j : Joueurs::Joueur::Groupe)
                j->main.clear();
     
     
            using namespace Joueurs;
     
            unsigned int i=0;
            int count =0;
            for(auto carte : Paquet){
                count++;
                Joueur::Groupe.at(i)->addCarte(carte);
                if(++i == Joueur::Groupe.size()) i=0;
            }
            Paquet.clear();
        }
    }
     
    #endif
    C++11 ou pas, il y a moyen de faire la même chose en C++03
    Nullius in verba

  3. #3
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Pour ma part je pense que je vais torcher avec une méthode statique de mise en correspondance qui contient une map statique remplie au premier usage.

    Mais je suis curieux de voir comment les autres développeurs abordent ce genre de mini-problèmes.
    Find me on github

  4. #4
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Tu es sûr que tu n’as pas shared_ptr ? Pas même dans tr1 ? Parce que tu peux utiliser des weak_ptr vers la map dans tes objets. Ça ne règle pas ton problème de durée de vie, mais ça te permet de gérer tranquillement le cas où la map n’existe plus et que tu cherches à l’utiliser dans tes objets (note : ça ressemble à une erreur de programmation, la factory devrait de fait avoir une durée de vie plus longue que les objets qu’elle crée si elle est aussi en charge de la gestion de la ressource).

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    (note : ça ressemble à une erreur de programmation, la factory devrait de fait avoir une durée de vie plus longue que les objets qu’elle crée si elle est aussi en charge de la gestion de la ressource).
    Oui c'est une erreur, c'est en la découvrant que j'ai écrit le topic. Et oui je suis sûr de ne pas avoir le tr1 ^^.
    Find me on github

  6. #6
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    j'ai mis longtemps à réagir, mais je voulais ajouter qu'il est préférable d'utiliser les namespaces dans ce genre de cas. Comme je ne retrouvais pas l'article où je l'ai lu, je n'ai rien dit mais voilà qui est chose faite :

    ici
    Nullius in verba

  7. #7
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Mmh, voyons si je peux apporter mon grain de sel dans l'affaire...

    Puisqu'il est question d'enum, je suppose que les chaines en question sont connues à la compilation.

    Une solution, en supposant que les valeurs d'enum n'ont pas de valeur intégrale spécifique :
    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
     
     
    enum Myenum
    {
        valeur1,
        valeur2,
        //...,
        valeurN,
     
        MyenumCount
    };
     
    #include <string>
     
    const std::string mapMyenum[MyenumCount] = {"valeur1", "valeur2", /*...,*/ "valeurN"};
     
    #include <algorithm>
     
    inline Myenum strToMyenum(const std::string& str)
    {
        return static_cast<Myenum>(std::find(mapMyenum, mapMyenum + MyenumCount, str) - mapMyenum);
    }
     
    #include <iostream>
     
    int main()
    {
        Myenum var = strToMyenum("valeur1");
        std::string var2 = mapMyenum[var];
     
        std::cout << var2 << std::endl;
    }
    solution testée qui compile en C++03.

    Voilà, solution assez légère sans map car elles seraient moins efficaces selon certains que des vector, alors je suppose que sur des tableaux statiques c'est encore plus vrai...

  8. #8
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Intéressant mais j'ai profité de la map pour avoir plusieurs chaînes qui renvoient la même valeur d'enum (mais c'est du luxe je pourrais m'en passer). J'ai déjà aussi utilisé la technique du MyenumCount mais j'aime pas trop car ça expose un symbole que l'utilisateur de la classe n'est pas censé utiliser.

    Ta méthode doit cependant bien fonctionner pour une petite liste !
    Find me on github

  9. #9
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    J'ai renommé ton MyenumCount en Unknown car ça a plus de sens pour l'utilisateur et ça permet de traiter proprement le cas ou on ne trouve pas dans la liste. Du coup j'ai utilisé ta technique avec le find, c'est plus simple
    Find me on github

  10. #10
    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,

    Ceci dit:

    Je présumes que ta collection (qu'il s'agisse d'une map ou d'un tableau, peu me chaut) n'est utile que pour certaines fonctions de tes différentes classes.

    Je présumes, aussi, que les classes qui manipule ta collection ont toutes trait à un domaine particulier, et que l'utilisation de ces classes est *relativement* restreint.

    A vrai dire, si la deuxième assertion est fausse, je me poserais énormément de question quant au desing général de l'application

    Si ces deux assertions sont correctes (mais le sont-elles seulement ) j'aurais tendance à dire que le meilleur moyen de s'assurer qu'un objet (la collection en l'occurrence) n'existe que de manière unique consiste à ... veiller à n'avoir qu'une seule variable représentant cet objet.

    Ne pourrais tu envisager de faire en sorte que ta collection n'existe qu'au niveau de "ce qui manipule les différentes classes" qui manipulent ta collection et de la passer (par référence de préférence constante) comme paramètre aux différentes fonctions qui en ont besoin
    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

  11. #11
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Le Unknown a en effet plus de sens pour l'utilisateur, moins pour le créateur mais c'est n'est peut-être pas le plus important.

    Je trouve qu'il manque une chose dans la STL/type_traits c'est un std::enum_count<Myenum>::value qui doit encore être réalisé à la main en C++11, c'est un manque.

  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 germinolegrand Voir le message
    Le Unknown a en effet plus de sens pour l'utilisateur, moins pour le créateur mais c'est n'est peut-être pas le plus important.

    Je trouve qu'il manque une chose dans la STL/type_traits c'est un std::enum_count<Myenum>::value qui doit encore être réalisé à la main en C++11, c'est un manque.
    Je ne suis pas sur du tout que cela aurait le moindre intérêt...

    Conceptuellement parlant, une valeur énumérée n'est jamais qu'une constante de compilation exactement comme une autre, à ceci près que le compilateur est en mesure de distinguer les "groupes de valeurs associées".

    Mais il est, par exemple, dans l'impossibilité de déterminer la plus haute valeur d'une énumération (je ne crois meme pas qu'il soit en mesure de le faire avec les énumération classes ) car il faut garder en mémoire le fait que, bien que tu puisse avoir des "trous" dans les valeur énumérées, les valeurs "intermédiaires" restent "valides"
    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 expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Ne pourrais tu envisager de faire en sorte que ta collection n'existe qu'au niveau de "ce qui manipule les différentes classes" qui manipulent ta collection et de la passer (par référence de préférence constante) comme paramètre aux différentes fonctions qui en ont besoin
    Je pourrais mais ça ne me plaît pas car l'existence de cet objet partagé est un détail d'implémentation qui ne concerne pas l'utilisateur de la classe (car il n'y en a qu'une) que je code, qui est une classe utilitaire destinée à être réutilisable à plusieurs endroits (classe d'algo jamais stockée comme membre d'une autre).
    Find me on github

  14. #14
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je ne suis pas sur du tout que cela aurait le moindre intérêt...

    Conceptuellement parlant, une valeur énumérée n'est jamais qu'une constante de compilation exactement comme une autre, à ceci près que le compilateur est en mesure de distinguer les "groupes de valeurs associées".

    Mais il est, par exemple, dans l'impossibilité de déterminer la plus haute valeur d'une énumération (je ne crois meme pas qu'il soit en mesure de le faire avec les énumération classes ) car il faut garder en mémoire le fait que, bien que tu puisse avoir des "trous" dans les valeur énumérées, les valeurs "intermédiaires" restent "valides"
    Oh que si, l'intérêt est énorme. A chaque fois qu'on doit écrire une valeur d'énumération COUNT, c'est qu'on manque d'un outils. Ainsi que l'a justement fait remarquer jblecanard, pour l'utilisateur ce COUNT est un peu hors sujet, de plus c'est une bidouille que ne marche que sur les énumérations auxquelles on n'a pas attribué de valeur entière (dans ce cas là on se retrouve forcé d'ajouter une valeur COUNT avec une valeur entière calculée à la main, la pire flexibilité qui soit).

    Pour répondre à la question, les enum class ne changent rien à l'affaire excepté qu'elles sont bien moins destinées à recueillir une valeur équivalente et pour le coup sont vraiment des étiquettes à usage sémantique (toujours transformables évidemment, mais vu tous les casts nécessaires il vaut mieux pour ce faire utiliser une enum dans un namespace).

    Un exemple tiré de mon serveur où la sémantique est pourrie par obligation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    namespace services
    {
    enum ServiceId: unsigned short
    {
        Network = 0,
        LC = 1,
        Connection = 2,
        Manager = 3,
        ClientCo = 4,
        SERVICES_COUNT = 5
    };
    }
    J'ai besoin du SERVICES_COUNT et je ne peux m'en passer : il représente le nombre total des services composant le serveur, et ma primitive de communication inter-thread requiert de connaître le nombre maximum de threads communicants. Je dois lui donner une valeur à la main parce que si pour l'instant tout est joli tout est rose, il y a de fortes chances que les valeurs entières prises par ces valeurs d'enum soient disparates...

  15. #15
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    A ce niveau là, on peut aussi envisager une combinaison class/enum
    par exemple, ces pistes sur stackoverflow sont intéressantes
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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

Discussions similaires

  1. visualisation des objets 3d par utilisation de opengl
    Par the_king dans le forum OpenGL
    Réponses: 16
    Dernier message: 16/05/2006, 16h43
  2. Grouper des objets partageant des propriétés
    Par camboui dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 06/04/2006, 19h01
  3. [JTabbedPane] partager des objet
    Par biozaxx dans le forum AWT/Swing
    Réponses: 5
    Dernier message: 21/03/2006, 14h10
  4. [Debutant][Conception] visibilité des objets de type conteneur
    Par thebloodyman dans le forum Général Java
    Réponses: 10
    Dernier message: 04/01/2006, 12h44
  5. Structures des objets.
    Par Zenol dans le forum Général JavaScript
    Réponses: 18
    Dernier message: 21/12/2005, 18h20

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