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 :

template et class


Sujet :

Langage C++

  1. #1
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut template et class
    Bonjour a tous,
    je suis un vrai debutant en c++ et je me trouve avec un grand code de c++ que je dois comprendre et debugger

    Ci-dessous une partie d'une class A qui contient une autre class B, un pointeur ptr est donne par (ligne 12 dans le code ci-dessous )
    B<T> *ptr = new B<T>(x);

    j'ai verifie dans le code il n'y a pas de "delete" pour le pointeur "ptr" je dois je l'ajouter et ou,

    il y a un destructeur dans le code pour la class A et non pour la class B, est ce que ceci est normal?

    le etoile "*" avant la fonction "ajout" (ligne 11)


    Merci de tout commentaire ou remarque pour comprendre ce morceau de code (au pt de vue programmation). Le programme se compile sans probleme, mais le debugger affiche une erruer dans la fonction ajout ligne 11.

    ==========
    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
    template <class T>
    class A;
    template <class T>
    class B{
         T val;
         B *alpha, *beta;
         B(const T &x) : val(x), alpha(0), beta(0) {}
         friend class A<T>;
    };
     
     
    template <class T>
    class A {
    /*...*/
        B<T> *ajout(const T &x) {
             B<T> *ptr = new B<T>(x);
             if (empty())
                 out = ptr;
             else
                 function1(out, ptr);
     
             return ptr;
          }
    /*... */
    };

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,

    Le principe général est de veiller à ce que la mémoire allouée dynamiquement pour un pointeur soit au plus tard libérée avant de perdre la variable de type pointeur qui permet d'y accéder...

    La place idéale pour la libération de la mémoire est souvent au niveau du destructeur de la classe, si du moins il est cohérent que l'objet dont la mémoire est allouée dynamiquement soit détruit en même temps que la classe qui fait référence à cet objet

    De plus, la présence d'un destructeur pour une classe se justifie quand... le destructeur ne peut pas se contenter du comportement implémenté par défaut par le compilateur, c'est à dire lorsque le destructeur doit faire autre chose que "simplement" détruire "statiquement" les différents membres de la classe.

    Les deux cas les plus courants dans lesquels définir toi même le destructeur sont:
    • le fait de prévoir un comportement polymorphe sur une hiérarchie de classes: il faut alors s'assurer que, lorsque l'on demandera de détruire un objet qui passe pour la classe de base, mais qui est en réalité un objet du type de la classe dérvivée, le bon destructeur ad-hoc soit invoqué (et donc déclarer le destructeur comme étant virtuel)
    • Le fait de prévoir une libération dynamique de mémoire allouée dynamiquement (typiquement: nécessité du recours à un delete ou à un delete[] pour contrebalancer une allocation dynamique de la mémoire effectuée par new ou new[] présente par ailleurs)

    Dans l'exemple que tu donnes, tu n'a pas recours à l'allocation dynamique de la mémoire pour ta classe B, et tu ne t'attend visiblement pas à ce que ta classe B soit dérivée, ce qui nécessiterait de s'assurer que le bon objet est détruit en temps utiles...

    Le comportement implémenté par défaut par le compilateur qui consiste à détruire les membre un à un dans l'ordre inverse de leur déclaration est donc tout à fait cohérent avec ta classe B... Et tu peux donc ne même pas déclarer le destrcuteur pour cette classe

    Par contre, en ce qui concerne ta classe A, tu manipules visiblement un pointeur avec une allocation dynamique de la mémoire qui justifie que tu prenne la précaution de t'assurer que cette mémoire est correctement libérée en temps opportun (le plus souvent dans le destructeur)...

    Pour forcer à la libération correcte de la mémoire, tu dois invoquer l'opérateur delete (ou delete[]) sur ce pointeur au plus tard au moment où tu va perdre la référence sur cette adresse mémoire, c'est à dire, au plus tard au moment de la destruction de l'instance de ta classe...

    Et tu te trouves donc face à l'obligation d'implémenter le destructeur
    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

  3. #3
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    Merci beaucoup de ta reponse. pour liberer la memoire allouer a ptr, je dois faire

    j'ai pas encore reussi a dechiffrer l'objet : B<T>(x).

    J'ai pas vraiment compris le morceau de code ci-dessous, que signifie le "*" devant la fonction ajout, ce morceau implement-il la fonction ajout.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    B<T> *ajout(const T &x) {
             B<T> *ptr = new B<T>(x);
             if (empty())
                 out = ptr;
             else
                 function1(out, ptr);
     
             return ptr;
          }

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    L'étoile juste avant le nom de la fonction indique que cette fonction va renvoyer un pointeur sur un objet de type B<T>
    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

  5. #5
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    si T est type float, que signifie le type B<T>, le B *alpha si j'ai pas compris la class B, ci-dessous, fait que intialise les variables val avec x, alpha et beta avec 0.

    Merci encore
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class B{
         T val;
         B *alpha, *beta;
         B(const T &x) : val(x), alpha(0), beta(0) {}
         friend class A<T>;
    };

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Lea classe template B ressemble à un nœud d'un arbre binaire: Valeur du nœud, pointeur vers le fils gauche, pointeur vers le fils droit;

    Si T est float, B<T> correspond à B<float>, en clair, un nœud dont la valeur est un float.

    Le constructeur de B prend une valeur en paramètre, et comme il construit un nœud "feuille", initialise ses pointeurs à zéro. N'oublie pas qu'un pointeur non-initialisé est le mal absolu...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    pour desallouer le pointeur ptr, j ai ajoute un delete dans le destructeur de la class A comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class A{
    public:
    A() : c(1) { r = 0; }
     ~A() { delete []  ptr; }
    /*..*/
    B<T> *ajout(const T &x) {
    /*..*/
     
    };

    le compilateur affiche l erreur suivante :

    erreur: «ptr» was not declared in this scope

    que dois je faire pour desallouer correctement le ptr.

    Merci

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    La classe A ne contient pas de variable membre nommée ptr.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    class A {
    /*...*/

    B<T> *ptr = new B<T>(x);

    }

    c'est a l'interieur de la fonction ajout ...

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Si on n'en croit le code fournit au début, B<T> *ptr = new B<T>(x); est une ligne de la méthode B<T> *ajout(const T &x). Donc la variable n'existe qu'à ce niveau pas au niveau de la classe.
    D'autre part, ton pointeur semble se ballader : dans out, dans function1 et retourné par ajout. Définis une fois pour toute qui à la responsabilité de ce pointeur et c'est lui qui l'alloue et le libère. Et même mieux, utilises un pointeur intelligent.

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Impossible de donner plus d'infos sans voir tout le code de la classe A.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    le ptr : B<T> *ptr = new B<T>(x); est effectivement une ligne de la fonction

    B<T> *ajout(const T &x)

    mais qui est a l'interieur de la class A,

    dois je faire un "delete []" a l'interieur de cette fonction apres le "return ptr"


    un pointeur declarer dynamiquement a l'interieur d'une fonction doit il etre desallouer a l'interieur de cette fonction

    (n'oublier pas je suis un debutant )



    PS : le code est vraiment tres grand, de plus il n est pas public ....

  13. #13
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par loisir1976 Voir le message
    le ptr : B<T> *ptr = new B<T>(x); est effectivement une ligne de la fonction

    B<T> *ajout(const T &x)

    mais qui est a l'interieur de la class A,

    dois je faire un "delete []" a l'interieur de cette fonction apres le "return ptr" (n'oublier pas je suis un debutant )
    Les variables de classes sont définies...dans la classe. Les variables d'une méthode restent locales à cette méthode.
    La gestion des pointeurs est toujours délicate. Donc, si tu es débutant, tu devrais commencer par t'en abstraire afin de maîtriser les autres aspects du langage.
    Quand libérer ton pointeur. Difficile à dire avec le peu de code que tu nous montre. Je vois trois problèmes :
    1/ Le pointeur peut être affecté à out :out = ptr;
    2/ Le pointeur est utilisé par une fonction function1(out, ptr);. Comment ?
    3/ Le pointeur est retourné par la méthode : return ptr;

    3 risques que le pointeur soit libéré à un endroit alors qu'il est encore utilisé à un autre. Donc, je ne vois pas comment te répondre à ta question. Une chose de sûr : ne pas le libérer dans la fonction si celle-ci doit le retourner à l'appelant.

  14. #14
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    1/ Le pointeur peut être affecté à out :out = ptr;
    2/ Le pointeur est utilisé par une fonction function1(out, ptr);. Comment ?
    3/ Le pointeur est retourné par la méthode : return ptr;
    3 risques que le pointeur soit libéré à un endroit alors qu'il est encore utilisé à un autre. Donc, je ne vois pas comment te répondre à ta question. Une chose de sûr : ne pas le libérer dans la fonction si celle-ci doit le retourner à l'appelant.
    Si j'ai compris la reponse :

    le pointeur ptr peut etre liberer par function1 ou autre methode utilisant function1

    le pointeur peut etre aussi liberer par une methode utlisant la fonction ajout

    par contre je ne voit pas comment l'affctation :out = ptr;
    peut etre un risque

    Merci

  15. #15
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Ca veut surtout dire que ton pointeur par dans la nature et que tu ne sais plus dire qui a encore un accès à cette adresse. C'est pourquoi c'est un risque à chaque fois que tu va choisir de faire un delete dessus quelque part. C'est la raison pour laquel : soit le pointeur reste dans A, soit tu utilises un pointeur intelligent (de type boost::shared_ptr).

  16. #16
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    je ne sais pas si ceci pourrait aider (a m'aider) a savoir ou liberer le ptr :

    la fonction function1, qui se trouve a l'interieur de la classe A contient ceci
    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
     
    class A {
    /*...*/
     
    B<T> *ajout(const T &x){
    /*...*/
    }
     
     void function1(B<T> *&f1, B<T> *f2) const {
     
                if (f2 == 0) return;
     
                if (f2->val < f1->val) {
                    /*...*/
                    f2->alpha = f1;
                    f1 = f2;
                }
                else {
                    f2->alpha = f1;
                    /*...*/
                    f1->beta = f2;
                }
            }
    };

  17. #17
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Effectivement, ça confirme mes inquiétudes Ton pointeur se retrouve à beaucoup d'endroit. Difficile de te donner un conseil pertinent sur où faire un delete sans connaître plus en avant ton architecture.
    Peux-tu utiliser remplacer tes pointeurs par une classe de pointeur intelligent (Boost.Smart Ptr ou sinon regarde de ce côté) ?

  18. #18
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    48
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 48
    Par défaut
    Bonjour,
    mon probleme est de ne pas savoir ou desallouer de la memoire alloue au pointeur ptr dans le morceau de code ci-dessous. le pointeur ptr est declare dans la fonction ajout (fichier A.h), et utilise dans la classe C fichier C.h.

    comment proceder pour savoir ou desallouer la memoire dans un code qui n est pas ecrit par soit meme, comment corrige des bugs liee a la memoire comme par exemple

    Warning: set address range perms: large range 107721600 (undefined)

    ce genre d erreur est il fatale

    Merci


    ===============
    fichier A.h
    ==================================
    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
     
    template <class T>
    class A;
    template <class T>
    class B{
         T val;
         B *alpha, *beta;
         B(const T &x) : val(x), alpha(0), beta(0) {}
         friend class A<T>;
    };
     
     
    template <class T>
    class A {
    /*...*/
        B<T> *ajout(const T &x) {
             B<T> *ptr = new B<T>(x);
    		/*...*/
             function1(out, ptr);
             return ptr;
          }
     
     
    void function1(B<T> *&f1, B<T> *f2) const {
     
                if (f2 == 0) return;
               /*...*/
                 f2->alpha = f1;
                f1 = f2;
               /*...*/
            }
     
     
    /*... */
    };
    ==========
    fichier C.h
    =============
    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
     
            #include "A.h"
            class C {
            protected:
            typedef A< > h;
            typedef B<> h2;
            /*...*/
     
            protected:
            h toto;
            h2 **ptr2;
            /*...*/
            public:
     
            C (arg 1 ,  ..arg n): bb(0)...{
            ptr2 = new h*[N];
            /*...*/
            }
     
            virtual ~C(){delete ptr2; /*..*/}	
     
            void init(){memset(ptr2,0,N*sizeof(h2*));}
     
            void function2(arg1..., int arg4){ ptr2[n]=toto.ajout(...); /*...*/;}
     
            void function3(arg1 ....){ ptr2[n]=toto.ajout(...); /*...*/;}
     
            /*...*/
            };

Discussions similaires

  1. "Template" de classe métier
    Par gbraux dans le forum Design Patterns
    Réponses: 3
    Dernier message: 20/11/2007, 10h37
  2. [Template] Problème Classe Template
    Par gimpycpu dans le forum Langage
    Réponses: 7
    Dernier message: 23/05/2007, 05h10
  3. Méthode template dans classe non template ?
    Par shenron666 dans le forum Langage
    Réponses: 12
    Dernier message: 04/09/2006, 17h50
  4. Utilisation de templates et classe en PHP?
    Par wkd dans le forum Langage
    Réponses: 1
    Dernier message: 01/09/2006, 15h36
  5. Template et classe "amie" ?
    Par tintin72 dans le forum Langage
    Réponses: 21
    Dernier message: 11/07/2006, 22h50

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