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 :

Destruction de plateau à HeroQuest


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 61
    Points : 92
    Points
    92
    Par défaut Destruction de plateau à HeroQuest
    Bonjour,

    Voilà, je m'excuse d'avance car le post risque d'être assez long, mon problème portant sur une implémentation objet assez conséquente.

    Je suis actuellement avec un ami en train de développer une version pc du jeu de plateau HeroQuest, en utilisant le C++ et la librarie graphique Allegro - je le précise, même si dans le cas présent on s'en moque un peu vous verrez -. Et nous rencontrons un problème au niveau de la destruction de notre objet plateau.

    C'est là que je dois m'expliquer. Je vous passe les méthodes à chaque fois, mais voici à quoi ressemblent nos classes :

    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
     
    class p_plateau
        {
        protected :
            std::string nom_quete;	// Nom de la quête
            std::string description_quete;	// Description de la quete
            int type_quete;		// 0 CHASSER / 1 SAUVER
            u_liste * cibles;		// La liste - chainée - des cibles
    				// de la quête
            p_salle * salles[34];		// Le tableau des salles du plateau.
            p_case * matrice_plateau[26][19];// La matrice des cases
            BITMAP * buffer_plateau;	// Le BITMAP * dans lequel on dessine
    	}
     
    class p_salle
        {
        protected :
            std::string adresse_texture;	// L'adresse de la texture des
    				// cases de la salle.
            int nb_cases;	// Nombre de case
            p_case ** cases;	// Tableau des cases de la salle
            u_liste * contenu;	// La liste - chainée - des positionnables
            BITMAP * texture;	// Le BITMAP * de la texture
        };
     
    class p_case : public u_point
        {
        protected :
            int visible;		// 0 Invisible - 1 Visible
            int bordure[4];	// Les propriétés des bords de la case 
    			// (0 rien/1 mur /2 porte/..)
            p_salle ** salles;	// Tableaux des salles auxquelles
    			// appartient la case
            u_liste * contenu;	// La liste - chainée - des positionnables
            BITMAP * buffer;	// Le BITMAP * dans lequel on dessine
           };
     
    /*	
    Exemple de positionnables : un gobelin, un héro, un piège hérissé de lance,
    un chevalet de torture, un sarcophage, bref n'importe quoi qui se pose
    sur le plateau.
    */
     
    class u_point
        {
        protected :
            int x;
            int y;
        };
     
    /* Deux classes pour la création et la gestion 
       de listes chainées d'élément de tous poils. */
     
    class u_liste
        {
        protected :
            u_noeud * tete;
            u_noeud * courant;
            int nb_elements;
        };
     
    class u_noeud
        {
        protected :
            void * valeur;
            u_noeud * suivant;
        };
    Au moment de la destruction du plateau, nous devons détruire un très grand nombre d'objets (494 cases, 34 salles, et tout les contenus), et il semblerait que nous nous emmelions un peu les pinceaux.
    Pour éviter toute tentative de destruction sur des objets déjà disparus, nous prenons pourtant soin, dans le destructeur de salle de passer à null le pointeur de chaque noeud de contenu et dans le destructeur de plateau d'en faire autant avec la liste des cibles. Ainsi tous les différents contenu ne sont plus connus qu'une fois, au travers du contenu des salles.

    Voici le code des différents destructeurs :

    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
    82
    83
    84
    85
    86
    87
    88
    89
     
    ~plateau()
        {
        int i, j;
     
        // Mise à NULL de tous les pointeur vers les objets cibles.
        if(cibles->get_tete()!=NULL)
            {
            cibles->init();
            while(cibles->is_suivant())
                {
                cibles->get_courant()->set_valeur(NULL);
                cibles->go_suivant();
                }
            }
        delete cibles;
     
        // Destruction des cases du plateau
        for(i=0;i<26;i++)
            {
            for(j=0;j<19;j++)
                {
                delete matrice_plateau[i][j];    
                }    
            }
        delete matrice_plateau;
     
        // Destruction des salles
        for(i=0;i<34;i++)
            {
            delete salles[i];    
            }
        delete salles;
     
        // Destruction du BITMAP * où dessiner le plateau
        destroy_bitmap(buffer_plateau);
        }
     
    ~p_salle()
        {
        // Mise à NULL de tous les pointeur vers les objets contenu dans la salle
        if(contenu->get_tete()!=NULL)
            {
            contenu->init();
            while(contenu->is_suivant())
                {
                contenu->get_courant()->set_valeur(NULL);
                contenu->go_suivant();
                }
            }
        delete contenu;
     
        // Destruction du tableau de cases
        delete cases;
     
        // Destruction de la texture en mémoire
        destroy_bitmap(texture);
        }
     
    ~p_case()
        {
        // Destruction du tableau de salles
        delete salles;
        // Destruction du contenu
        //  - cette fois les pointeur on concervés leur valeur -
        delete contenu;
     
        destroy_bitmap(buffer);
        }
     
    ~u_liste()
        {
        int i;
        u_noeud * parcours=tete, * suivant;
     
        // Par cours de la liste et destruction de chacun de ses noeuds.
        for(i=0;i<nb_elements;i++)
            {
            suivant=parcours->get_suivant();
            delete parcours;
            parcours=suivant;
            }
        }
     
    ~u_noeud()
        {
        // Destruction de l'objet porté par le noeud
        delete valeur;
        }
    Voilà, merci d'avoir eu le courage de lire tout ceci, et merci d'avance à tout ceux pourrait nous apporter leur aide.

    Parce que la solution pour que ca tourne pour le moment, c'est de commenter intégralement le destructeur de plateau :=°

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Je ne sais pas si les données membres qui ont le même type et le même nom dans les différentes classes désignent le même objet physique, mais si c'est le cas alors oui tu détruis ces objets plusieurs fois.

    Pourquoi ne pas utiliser std::list pour tes listes chaînées ? Et correctement définir quelle (seule et unique) classe va posséder chacune et gérer sa durée de vie ? Ou si c'est plus compliqué (tu ne sais pas qui va devoir détruire qui), pourquoi ne pas utiliser des pointeurs intelligents ?
    http://miles.developpez.com/tutoriel...oost/smartptrs

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 61
    Points : 92
    Points
    92
    Par défaut
    Citation Envoyé par Laurent Gomila
    des pointeurs intelligents ?
    Humm, euh j'avoue, c'est la première fois que j'entends parler de pointeur intelligents... J'ai parcouru rapidement le tuto du lien, ca a l'air relativement puissant, une fois qu'on sait s'en servir :/

    Et je dois dire qu'au point où nous en sommes - et avec le délai qu'il nous reste (9 jours :$ ) -, je nous vois mal reprendre l'ensemble pour gérer des pointeurs intelligents....

    Existerait-il un moyen - plus ou moins simple dans la mesure du possible - de tester où ca plante ?

    Folken, étudiant codant son premier jeu en galère :/

  4. #4
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    C'est simple à utiliser pourtant
    Dans ton cas, pour commencer, tu remplaces tes pointeurs par des pointeurs intelligents, aucun souci.
    Pour la suite, essaie d'éviter de recoder une liste maison en C alors que ça existe en C++ - std::list - et que c'est super bien géré - avec des pointeurs intelligents, c'est encore plus puissant -, et que ça t'évite carrément d'avoir un destructeur. Durée de l'opération de refactoring, environ 1/2 journée, je viens de le faire pour un autre tuto avec gestion des pointeurs intelligents à ajouter et une liste maison à supprimer.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 61
    Points : 92
    Points
    92
    Par défaut
    Je vais me pencher sur l'utilisation des std::list et des pointeurs intelligents. Je pense en avoir effectivement pour une demi-journée de boulot, je verrais ca demain matin.

    Merci à vous pour les conseils.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 61
    Points : 92
    Points
    92
    Par défaut
    Je me permet de remonter le sujet car nous en arrivons à ... une nouvelle impasse ^^

    Pour gérer les contenu, nous voulions utiliser std::list plutot que notre classe maison - effectivement, c'est beaucoup mieux -, mais en même temps, nous aimerions utiliser les pointeurs intelligents - et en particulier les shared_ptr - pour gérer les objets présents sur le plateau et dans les inventaires - avec toutes les références multiples que je vous expliquait plus haut -.

    Mais les shared_ptr sont apparemment incompatibles avec une gestion par liste chainée...

    Devons nous perdre la simplicité de gestion des std::list, et nous repencher sérieusement sur nos destructeur pour désallouer convenablement notre mémoire, ou bien au contraire conserver cette facilité de gestion des objets, et retourner jouer avec des tableaux ? ...

    Un conseil ? Merci d'avance.

  7. #7
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Qui a dit qu'ils étaient incompatibles ? Les std::auto_ptr sont incompatibles, et les boost::shared_ptr résolvent le problème des std::auto_ptr : ils partagent la responsabilité au lieu de la transférer.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 61
    Points : 92
    Points
    92
    Par défaut
    Citation Envoyé par Miles
    Qui a dit qu'ils étaient incompatibles ?
    Citation Envoyé par Documentation Boost/descriptif du shared_ptr/FAQ
    Q. Why doesn't shared_ptr use a linked list implementation?

    A. A linked list implementation does not offer enough advantages to offset the added cost of an extra pointer. See timings page. In addition, it is expensive to make a linked list implementation thread safe.

    Mon anglais technique reste approximatif, mais en nous y mettant à deux nous avions compris ce passage comme une incompatibilité. Cela tombait bien en plus puisque cela expliquait le fait que notre compilateur refuse d'aller plus loin que nos fichiers header, ne reconnaissant pas la déclaration du type "std::list<boost::shared_ptr<e_element>> cibles;" comme celle d'un attribut à l'intérieur de nos classes - alors que nous avons télécharger et installer boost et que les bons include sont faits -.
    A la place, il essaie de reconnaitre contenu comme une classe, obligatoirement non déclarée.

    A moins que nous n'ayons pas tout compris à l'utilisation ... :/

  9. #9
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Non, ça veut dire que shared_ptr n'utilise pas une liste pour stocker les objets qui pointent vers l'entité commune, le pointeur surveillé, histoire de performance et non de compatibilité.
    Ca, "std::list<boost::shared_ptr<e_element>>", ça ne marche pas, oui, mais ça "std::list<boost::shared_ptr<e_element> >" oui, attention aux > > de fin ! Attention aussi au fait qu'il faut inclure 2 headers, <list> et <boost/shared_ptr>
    Tu imagines que si ça ne marchait pas, je l'aurai indiqué dans le tuto

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 61
    Points : 92
    Points
    92
    Par défaut
    Citation Envoyé par Miles
    Tu imagines que si ça ne marchait pas, je l'aurai indiqué dans le tuto
    Effectivement, maintenant ca passe à la compilation. Une fois de plus, nous avons déplacé le problème, magnifique non ? ...
    Il semblerait que shared_ptr<class> n'accepte qu'une class qui soit intégralement définie. Il nous reste à trouver comment définir trois classes faisant référence à elle-même à un moment ou à un autre, tout en définisant entièrement chacune d'entre elles avant les deux autres :/

    [ Edit ]

    Problème résolu, merci encore à tous. Le moins qu'on puisse dire est que l'on aura enormement appris en deux jours - surtout sur notre ignorance ^^ -.

    [ /Edit ]

  11. #11
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Effectivement, ça, je ne l'ai pas indiqué, mais la classe doit être entièrement définie pour le destructeur de shared_ptr.

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

Discussions similaires

  1. destruction d'une classe qui herite de CDialog
    Par philippe V dans le forum MFC
    Réponses: 2
    Dernier message: 03/02/2004, 17h39
  2. Réponses: 2
    Dernier message: 17/08/2003, 20h07
  3. Probleme de destruction
    Par Merluco dans le forum Langage
    Réponses: 6
    Dernier message: 30/06/2003, 13h51
  4. Création/Destruction
    Par HT dans le forum Langage
    Réponses: 5
    Dernier message: 22/05/2003, 17h04
  5. Réponses: 7
    Dernier message: 18/04/2003, 10h02

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