Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tableau 2D d'objet

Une horreur!!!

Sujet résolu
    5 mai 2008 à 21:22:22

    Bonjour

    Je tente désespérément de réussir à créer un Tableau 2D avec à l'intérieur l'objet Obj (dont voici la code)

    class Obj
    {
        public:
    
        Obj()
        {
            objet=0;
            nom="";
        }
        Obj(const Obj &objetACopier)
        {
            nom = objetACopier.nom;
            objet = new WPos(*(objetACopier.objet));
        }
        void setObj(WPos* const type=0 )
        {objet=type;}
        void setNom(std::string const nnom="" )
        {nom=nnom;}
        WPos* GetObj() const
        {return objet;}
        std::string GetNom() const
        {return nom;}
        Obj operator=(const Obj &objetACopier)
        {
            nom = objetACopier.nom;
            objet = new WPos(*(objetACopier.objet));
            return *this;
        }
        Obj operator=(const Obj *objetACopier)
        {
            nom = objetACopier->nom;
            objet = new WPos(*(objetACopier->objet));
            return *this;
        }
        ~Obj()
        {delete objet;}
    
        private:
    
        WPos *objet;
        std::string nom;
    };
    

    Mon problème c'est que quelque soit la manière dont je traite le problème j'ai le droit à un magnifique
    PuzzPack.exe a rencontré un problème et doit fermer. Nous vous prions de nous excuser pour le désagrément encouru.


    J'ai essayé les tableau dynamique
    #include <iostream>
    #include <string>
    #include <SFML/Graphics.hpp>
    
    #include "Matrice.h"
    
    using namespace std;
    
    Matrice::Matrice()//Constructeur ne sert à rien
    {}
    
    void Matrice::setTaille(int tx,int ty)//Sert à fixer la taille du tableau dont on vient d'apprendre la taille
    {
        m_taille_x = tx;
        m_taille_y = ty;
    
        m_matrice = new Obj*[tx];
        for(int i=0;i<15;i++)
        {m_matrice[i] = new Obj[ty];}
        Obj* base = new Obj;
        for (int i = 0; i <tx; ++i)
        {
            for (int j = 0; j <ty; ++j)
            {m_matrice[i][j] = base;}//Ici ça bogue à l'exécution 
        }
        cout<<"Allocation réalisée avec succés"<<endl;
    }
    
    void Matrice::insert(int x,int y,string nnom,WPos *type)
    {
        m_matrice[x/30][y/30].setNom(nnom);
        m_matrice[x/30][y/30].setObj(type);
    }
    Matrice::~Matrice()
    {
        for(int i=0;i<15;i++)
        {delete[] m_matrice[i];}
        delete[] m_matrice;
    }
    


    Avec dans Matrice.h
    Obj** m_matrice;
    


    Avec les vector ça ne marche pas mieux
    void Matrice::setTaille(int tx,int ty)
    {
        m_taille_x = tx;
        m_taille_y = ty;
        Obj base;
        cout<<"1";
        m_matrice.resize(tx);
        cout<<"2";
        for (int i = 0; i <tx; ++i)
        {
            for (int j = 0; j <ty; ++j)
            {m_matrice[i].push_back(base);}
        }
        cout<<"Allocation réalisée avec succés"<<endl;
    }
    


    Avec dans Matrice.h

    std::vector< std::vector<Obj> > m_matrice;
    


    <vector> etant bien entendu inclu dans Matrice.h

    Je ne vois vraiment pas comment réussir ce problème
    Merci de votre aide
    Adastre
    • Partager sur Facebook
    • Partager sur Twitter
      5 mai 2008 à 22:09:22

      Il me semble qu'un tableau 2d est comme ceci
      tableau [x][y]
      je ne sais pas si tu peux faire ca avec des vecteurs...
      • Partager sur Facebook
      • Partager sur Twitter
        5 mai 2008 à 22:14:39

        On peut éviter l'utilisation des tableaux en C++ grâce aux conteneurs de la STL.

        Vecteurs 2D c'est pas très beau ; il y a un beau diagramme pour aider à choisir un conteneur selon ses besoins dans la FAQ de developpez.com :
        http://cpp.developpez.com/faq/cpp/imag [...] conteneur.gif
        • Partager sur Facebook
        • Partager sur Twitter
          6 mai 2008 à 16:26:40

          les std::vector 2d c'est très acceptables. Aucun conteneur de la STL ne peut contenir une matrice.

          le problème c'est qu'on ne fait pas de new avec les std::vector!

          Elle sert à quoi la classe Obj? et WPos c'est quoi?

          Si le but de Obj c'est d'associer un nom à un objet aussi bien utiliser des std::pair...

          Ensuite c'est normal que ça plante parce que tu appels le constructeur de copie (ou l'opérateur = dans la version avec les tableaux dynamiques). Si tu regardes ces fonctions tu fais un new avec un déréférencement de l'objet de ObjetACopier. ObjetACopier étant 'Obj base' qui a été créé avec le constructeur par défaut...

          ...

          ...

          Oui, tu essais de déréférencer un pointeur qui pointe sur 0.
          • Partager sur Facebook
          • Partager sur Twitter
            6 mai 2008 à 19:46:54

            Oui le but de Obj c'est bien d'associer un nom à un objet (WPos étant l'objet de base de mon jeu , c'est comme QWidget pour simplifier)

            Citation : MatteX

            Si le but de Obj c'est d'associer un nom à un objet aussi bien utiliser des std::pair...


            -> Comment ça marche??

            Je ne comprends pas cette histoire de "déréférencer un pointeur qui pointe sur 0."
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              6 mai 2008 à 19:57:47

              Citation : Adastre

              Citation : MatteX

              Si le but de Obj c'est d'associer un nom à un objet aussi bien utiliser des std::pair...


              -> Comment ça marche??


              1er réflex : Google.
              • Partager sur Facebook
              • Partager sur Twitter
                6 mai 2008 à 20:03:28

                l'opérateur '*' devant une entité c'est l'opérateur de déréférencement. ( On va donc lire la valeur à l'adresse pointée)

                si le membre objet de ta variable base dans la méthode SetTaille est à 0. Lorsque tu vas le copier (ce qui est automatique) et que tu vas passer par

                objet = new WPos(*(objetACopier->objet));
                


                Tu vas donc essayer d'accéder à 0 : Ce qui est interdit.
                • Partager sur Facebook
                • Partager sur Twitter
                  6 mai 2008 à 20:41:18

                  Donc si j'ai bien compris ,il me suffit d'allouer la variable membre objet dans l'objet Obj pour que ça marche

                  -> C'est effectivement ce qui se passe

                  Mais es-ce que la solution est identique pour utiliser les vector ?

                  @Huira-> j'aime pas google
                  • Partager sur Facebook
                  • Partager sur Twitter
                    6 mai 2008 à 21:05:15

                    Outre le problème du pointeur null qui pourra se régler facilement par un code tel que

                    Obj(const Obj &objetACopier)
                    {
                        nom = objetACopier.nom;
                        if (objetACopier.objet != 0)
                            objet = new WPos(*(objetACopier.objet));
                        else
                            objet = 0;
                    }
                    

                    et idem dans les opérateurs =

                    il y a quelques petites choses qui me turlupinent, notemment dans la version avec les tableaux 2D à la mode pointeurs.

                    void Matrice::setTaille(int tx,int ty)
                    {
                        m_taille_x = tx;
                        m_taille_y = ty;
                    
                        m_matrice = new Obj*[tx];
                        for(int i=0;i<15;i++)
                        {m_matrice[i] = new Obj[ty];}
                        Obj* base = new Obj;
                        for (int i = 0; i <tx; ++i)
                        {
                            for (int j = 0; j <ty; ++j)
                            {m_matrice[i][j] = base;}//Ici ça bogue à l'exécution 
                        }
                        cout<<"Allocation réalisée avec succés"<<endl;
                    }
                    

                    Ligne 7 : pourquoi ce 15 ? Tu naurais pas gardé une vieille constante que tu devais remplacer par tx ?
                    lignes 9 et 13 : Tu crée un pointeur pour le passer par l'opérateur = prévu à cet effet. Puisque de toutes façons tu copie l'objet, es-tu vraiment obligé de passer par un pointeur ?
                    Et enfin, pourquoi tu fais deux boucles ? tu ne peux pas caser ton "m_matrice[i] = new Obj[ty]; " entre les deux for de la boucle imbriqué ?

                    Obj operator=(const Obj &objetACopier)
                    {
                        nom = objetACopier.nom;
                        objet = new WPos(*(objetACopier.objet));
                        return *this;
                    }
                    
                    Obj operator=(const Obj *objetACopier)
                    {
                        nom = objetACopier->nom;
                        objet = new WPos(*(objetACopier->objet));
                        return *this;
                    }
                    


                    Il y avait déjà le problème de la copie en profondeur du pointeur null, mais il y en a un plus viscieux qui se cache là ! Genre de bug qui ne fait pas planter le programme mais qui le ronge petit a petit pour brouiller les pistes ! J'ai nommé la fuite mémoire \o/

                    S'il y a déjà un objet d'initialisé et que tu utilise l'opérateur =, tu perds l'objet original sans le détruire, exemple :
                    #include "Obj.h"
                    
                    int main() {
                       while(true) {
                          /* Faire des choses */
                    
                          Obj obj1;
                          Obj obj2;
                          obj1.setObj();
                          obj2.setObj();
                          obj1 = obj2;
                    
                          /* Faire d'autres choses*/
                       }
                    }
                    

                    A chaque passage dans la boucle un premier objet est créé par "obj1.setObj(); ", un second est créé par "obj2.setObj(); ", le second est copié dans obj1 par "obj1 = obj2; " ce qui en crée effectivement un 3eme.

                    A la fin de la boucle obj1 et obj2 sont détruits, emportant dans leur chute le second et le 3eme objet WPos... mais le premier reste, planqué quelque part dans l'imensité de la mémoire vive.

                    Puisque t'es en train de faire un jeu, il se peut que quelqu'un aime ton jeu, y passe des heures... et finisse par planter parceque ses 4Go de mémoire vive n'ont plus suffit à garder tous les WPos perdus :D

                    Donc au final je préconise ça :

                    Obj(const Obj &objetACopier)
                    {
                        nom = objetACopier.nom;
                    
                        if (objetACopier.objet != 0)
                            objet = new WPos(*(objetACopier.objet));
                        else
                            objet = 0;
                    }
                    
                    Obj operator=(const Obj &objetACopier)
                    {
                        nom = objetACopier.nom;
                        
                        if (objet != 0)
                            delete objet;
                    
                        if (objetACopier.objet != 0)
                            objet = new WPos(*(objetACopier.objet));
                        else
                            objet = 0;
                    
                        return *this;
                    }
                    
                    Obj operator=(const Obj *objetACopier)
                    {
                        nom = objetACopier->nom;
                    
                        if (objet != 0)
                            delete objet;
                    
                        if (objetACopier->objet != 0)
                            objet = new WPos(*(objetACopier->objet));
                        else
                            objet = 0;
                    
                        return *this;
                    }
                    




                    Enjoy o/
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      6 mai 2008 à 21:20:01

                      Citation : Adastre

                      @Huira-> j'aime pas Google

                      Ok, alors je corrige :
                      Premier réflex : Rechercher.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        6 mai 2008 à 21:21:28

                        Effectivement ça marche
                        Merci beaucoup à tous
                        • Partager sur Facebook
                        • Partager sur Twitter
                          6 mai 2008 à 21:30:28

                          std::vector copie. Donc tu dois assurer que ton constructeur par copie est sécuritaire.

                          Ensuite que ce soit Google ou autre une piste aussi grande que std::pair tu devrais être capable de trouver de la documentation

                          gotapi.com
                          dinkumware.com
                          roguewave.com
                          sgi.com
                          msdn.com

                          meme cppreference.com au pire.

                          si tu veux un tableau de pairs uniques tu n'as qu'à utiliser std::map. Et si tu veux un tableau de tableaux de pairs uniques tu n'as qu'à utiliser un

                          std::vector<std::map<std::string, WPos> > m_matrice;
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                            6 mai 2008 à 22:02:20

                            Le contructeur de copie plantera en release (pas de sens de détruire un truc qui pointe n'importe où)
                            Les opérateurs d'affectations fuient.
                            • Partager sur Facebook
                            • Partager sur Twitter
                            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                              6 mai 2008 à 22:23:48

                              Erf, bien vu pour le constructeur, j'ai corrigé ma réponse ;)
                              • Partager sur Facebook
                              • Partager sur Twitter
                                6 mai 2008 à 22:33:10

                                Reste l'opérateur d'affectation qui ne résistera pas à une exception.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                  6 mai 2008 à 22:47:12

                                  S'il y a une exception ça ne enmpechera completement la copie et on devra re-throw, non ?

                                  Quite à ce que l'appelant se prenne une exception dans la gueule autant ne pas s'en occuper ici :D (Inki = flemmard)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    6 mai 2008 à 23:36:34

                                    Si exception, ton opérateur se laisse son objet dans un état muté, et instable.
                                    (une solution est dans la FAQ C++ de developpez)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.

                                    Tableau 2D d'objet

                                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                    • Editeur
                                    • Markdown