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

Langage C++ Discussion :

Classe Liste générique avec template


Sujet :

Langage C++

  1. #1
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut Classe Liste générique avec template
    Bonsoir,

    Les Topics se suivent...mais ne se ressemble pas! J'ai un petit, bon d'accord un gros problème avec un bout de code qui concerne une liste générique doublement chaînée lorsque je l'utilise avec des vecteurs (pas ceux de la STL...).
    Le problème est une fuite mémoire assez bizarroïde (c'est le propre d'une fuite mémoire?) qui se passe quand je lance le programme et qui freeze DrWatson (le débugeur post-mortem qui arrive après le crash de l'application) une 30aine de seconde...Donc réflexe, je lance le débugueur de C::B et là.... PATATRAAAAA, ça fonctionne au poil...

    Du côté liste :
    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
     
      template<typename TYPE, unsigned int nb_cur>
      struct LIST
        {
            ///Data level
            struct ELMT
            {
                ELMT* prev;
                TYPE data;
                ELMT* next;
     
                ELMT(ELMT* p, TYPE& dat) : data(dat)
                {
                    prev = p;
                }
            };
     
            ///Data
            unsigned int length;
            ELMT *fst;
            ELMT *cur[nb_cur];
            ELMT *lst;
     
            LIST()
            {
                unsigned int i;
     
                length = 0;
     
                fst = NULL;
                lst = NULL;
     
                for(i=0; i<nb_cur; i++)
                    cur[i]=NULL;
     
                return ;
            }
     
            unsigned int push(TYPE& data)
            {
                //Data problem
                if( fst==NULL )
                {
                    fst = new ELMT(NULL, data);
                    lst = fst;
                }
                else
                {
                    lst->next = new ELMT(lst, data);
                    lst = lst->next;
                }
     
                length++;
                return length;
            }
        };
    Du côté vecteur (dim étant un entier, non signé, prédéfini)
    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
     
          struct VECTOR
            {
                float* data;
     
                VECTOR()
                {
                    data = new float(dim);
                    return ;
                }
     
                VECTOR(VECTOR& v)
                {
                    unsigned int i;
                    data = new float(dim);
     
                    for(i=0; i<dim; i++)
                        *(data+i) = *(v.data+i);
     
                    return ;
                }
     
                VECTOR& operator= (const VECTOR& v)
                {
                    unsigned int i;
     
                    for(i=0; i<dim; i++)
                        *(data+i) = *(v.data+i);
     
                    return *this;
                }
       };
    (bien entendu j'ai allégé un peu le code...)

    et pour le test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    VECTOR a;
    LIST<VECTOR,1> lst;
    lst.push(a);
    (dois-je aussi utiliser plutôt memcpy et memset pour mes opérations sur des tableaux???)

    Voili, voilou, je vous remercie de m'aider.

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Tu n'as pas de destructeurs dans ton code ?
    Ensuite, que se passe-t-il si l'utilisateur essaye de copier un objet de type LIST ?
    A part ça, il est plus courant d'avoir comme signature pour un constructeur de copie : VECTOR(VECTOR const & v) au lieu de VECTOR(VECTOR& v)
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Ce code
    alloue un float dans le tas, lui affecte la valeur "dim" et renvoie un pointeur dessus.
    Je suppose que tu souhaites plutôt allouer un tableau de 10 float :
    (Attention à bien utiliser delete[] au lieu de delete dans le destructeur)

  4. #4
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    Merci beaucoup pour vos réponses ...

    En fait je n'ai pas publié les destructeurs mais ils sont dans le code compilé (et dans leurs classes respectives)...
    Pour List :
    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
     
            ~LIST()
            {
                while(length>0) drop();
            }
     
            unsigned int drop(void)
            {
                if( lst!=NULL )
                {
                    if( lst->prev!=NULL )
                    {
                        lst = lst->prev;
                        delete lst->next;
                    }
                    else
                    {
                        fst = NULL;
                        delete lst;
                    }
                    length--;
                }
     
                return length;
            }
    Pour Vector :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
                ~VECTOR()
                {
                    delete[] data;
                }
    Par contre je n'ai pas encore implémenté la copie de LIST...
    Merci, pour l'erreur du new (() au lieu de []) que je n'avais pas vu ...

    Petite question 1 : est-il plus propre d'utiliser les memset et memcpy que des boucles for?
    Petite question 10 : sur l'utilisation du mot clé const, j'ai repéré cette adresse. Faut-il toujours suivre ces conseils comme des idiomes de programmation???

    Merci de votre aide.

  5. #5
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    Citation Envoyé par TNT89 Voir le message
    Petite question 10 : sur l'utilisation du mot clé const, j'ai repéré cette adresse. Faut-il toujours suivre ces conseils comme des idiomes de programmation???
    Je ne vois aucune raison valide de ne pas produire du code correcte au niveau des const.

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

    A vrai dire, il y a un certain nombre de chose que je ne comprend pas vraiment...

    Par exemple, l'usage que tu peux avoir du membre (tableau de pointeur de type ELEM) cur...

    Typiquement, les listes chainées sont utilisée, justement, pour ne pas devoir recourir à un tableau contigu d'éléments (même s'il doit s'agir d'un tableau de pointeurs) pour en gérer le contenu...

    D'autent plus que chaque élément a une référence vers l'élément qui le suit, et comme nous parlons d'une liste doublement chainée, une référence vers l'élément qui le précède...

    L'idée générale d'une liste simplement chainée est donc de n'allouer qu'un seul élément à chaque fois, et "sur demande" (au moment où l'on décide de rajouter un élément)

    De plus, comme pour tout élément de n'importe quelle structure dynamique (pile, file, liste, arbre binaire), la création d'un élément doit être simplifiée au maximum:
    tu alloue l'espace mémoire pour l'élément, tu initialise l'objet qu'il contient, et tu initialise les références vers les éléments "adjacents" à NULL.

    C'est en effet du seul role de la structure dynamique d'aller "chipoter" à ces références pour l'insérer... dans la structure dynamique.

    (au fait, évite de choisir des noms tout en majuscules pour tes structures... c'est généralement réservé aux définitions préprocesseur )

    Au final, ta structure devrait prendre (hors template) une forme proche de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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
    90
    91
    class Liste
    {
        public:
            class Element
            {
                public:
                    Element(Type const& value):value(value),prev(0),next(0){}
                    ~Element(){/* rien à faire */}
                    /* les acces aux éléments précédents et suivants */
                    Element* operator++(){return next;}
                    Element* operator--(){return prev;}
                    Element const * operator++ const{return next;}
                    Element const * operator-- const{return prev;}
                    /* les acces a la valeur contenue */
                    Type & operator*(){return value;}
                    Type const & operator*() const{return value;}
                    Type & operator->(){return value;}
                    Type const & operator() const{return value;}
                private:
                    Type value;
                    Element* prev;
                    Element* next;
                    /* la liste doit pouvoir accéder aux pointeurs privés */
                    friend class Liste;
            }
            Liste():msize(0),first(0),last(0){}
            /* les fonctions suivantes ne devraient pas être inline
             * Si elles le sont, c'est juste par flegme...
             */
            ~Liste()
            {
                while(first)
                {
                    Element* temp=first->next;
                    delete first;
                    first=temp;
                }
            }
            void push_back(Type const& value)
            {
                Element* temp=new Element(value);
                if(!first)
                    first=temp;
                temp->prev=last;
                if(last)
                    last->next=temp;
                last = temp;
            }
            void insert(Element* prev, Type const & value)
            {
                if(prev == last || (prev==0 && last==0))
                    push_back(value);
                else
                {
                    ASSERT(prev!=0);
                    Element* temp=new Element(value);
                    if(prev->next)
                    {
                        temp->next = prev->next;
                        prev->next->prev = temp;
                    }
                    prev->next = temp;
                    temp->prev = prev;
                }
            }
            size_t size() const
            {
                if (!first)
                    return 0;
                size_t ret=0;
                Element* temp=first;
                while(temp)
                {
                    ++ret;
                     tem=temp->next;
                }
                return ret;
            }
            /* il faudrait aussi de quoi supprimer un élément et, pourquoi pas,
             * un ensemble d'éléments adjacents
             * les fonctions suivantes peuvent être inline 
             */
            bool empty() const{return first!=0;}
            Element* begin(){return first;}
            Element* end(){return 0;}
            Element const * begin() const{return first;}
            Element const * end() const{return 0;}
        private:
            Element* first;
            Element* last;
    };
    (code créé "from scratch", non testé, mais normalement correct )
    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

  7. #7
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    Le tableau de pointeurs 'cur' me sert pour définir un ensemble de curseurs pointant donc vers certains éléments du tableau...Cela me permet de faire des traitements propre à chaque liste en se souvenant de certaines caractéristiques (d'où un tableau de taille fixée)...
    Enfin après il y a surement possibilité de faire mieux...(mais le mieux est l'ennemi du bien )...

  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
    Citation Envoyé par TNT89 Voir le message
    Le tableau de pointeurs 'cur' me sert pour définir un ensemble de curseurs pointant donc vers certains éléments du tableau...Cela me permet de faire des traitements propre à chaque liste en se souvenant de certaines caractéristiques (d'où un tableau de taille fixée)...
    Sauf que cela n'entre pas dans les responsabilités de la liste...

    La seule responsabilité de la liste, c'est de maintenir l'ensemble des éléments en un tout cohérent, et c'est déjà amplement suffisant.

    Si tu veux disposer, pour un usage particulier, d'une structure qui permette de garder un index de certains éléments de la liste sur lesquelles certaines actions ont été effectuées, ca doit être de la responsabilité d'autre chose, qui disposera d'une liste et d'un tableau d'éléments
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    c'est plutôt philosophique donc...J'avais envie d'en-capsuler ces deux objets car je n'ai pas besoin de listes au sens classique du terme...et ce n'est pas destiné à être une librairie...

    Je vous remercie de vos remarques :

  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
    Ce n'est absolument pas "philosophique"...

    C'est la seule manière de s'assurer que l'on évite des problèmes qui apparaitront systématiquement du fait que tu en demande trop à une seule et unique chose...

    De plus, cela permet de "modulariser" beaucoup mieux ton programme
    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

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 30/12/2009, 20h44
  2. Classe pile generique avec template
    Par marbouchi dans le forum Langage
    Réponses: 10
    Dernier message: 10/05/2009, 10h10
  3. Tri d'une liste avec template
    Par Invité dans le forum Langage
    Réponses: 14
    Dernier message: 24/12/2007, 13h28
  4. Pb avec template list
    Par olive_le_malin dans le forum Langage
    Réponses: 10
    Dernier message: 16/11/2006, 02h05
  5. Utilisation de la classe List de STL avec wxWidgets
    Par aoyou dans le forum wxWidgets
    Réponses: 7
    Dernier message: 10/03/2005, 17h41

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