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 :

[Débutant] Constructeur ~Destructeur


Sujet :

C++

  1. #1
    Membre éclairé Avatar de grabriel
    Inscrit en
    Septembre 2006
    Messages
    946
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 946
    Points : 730
    Points
    730
    Par défaut [Débutant] Constructeur ~Destructeur
    Bonjour,

    Concernant les constructeurs et les destructeurs j'ai lu sur un forum (peut être ici) que le fait d'utiliser new peux entrainer des fuites mémoires!!

    Ma question est quelle est la meilleur façon de construire et détruire un objet?

    J'ai un peu de mal avec ce concept? le jour où il y aura un garbage collector....


    Est ce que ceci est bon?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    maClasse::maClasse(int unEntier, char* unPointeurChar)
    {
        unEntier = 3;
        unPointeurChar = "aa";
    }
     
    maClasse::~maClasse()
    {
        delete[] entier, unPointeurChar;
    }
    Avec un header qui déclare ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class maClasse
    {
      public :
        maClasse();
        ~maClasse();
     
      private :
        int unEntier;
        char *unPointeurChar;
    }
    Merci!

  2. #2
    Membre habitué
    Inscrit en
    Avril 2008
    Messages
    155
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 155
    Points : 158
    Points
    158
    Par défaut
    ben oui:
    si tu as

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class maClasse
    {
      public :
        maClasse();
        ~maClasse();
     
      private :    
        char *unPointeurChar;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    maClasse::maClasse(int unEntier, char* unPointeurChar)
    {
        unEntier = 3;
        unPointeurChar = "aa";
    }
     
    maClasse::~maClasse()
    {
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for(;;)
    {
     maClase();
    }
    a chaque passage de boucle il y a 2 octets qui sont perdus.

    En règle générale, évite d'utiliser les new/delete...
    Ou alors assure toi bien de faire un delete sur le pointeur attribut.

  3. #3
    Membre habitué
    Inscrit en
    Avril 2008
    Messages
    155
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 155
    Points : 158
    Points
    158
    Par défaut
    oups je me suis planté de constructeur mais tu as compris

  4. #4
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 73
    Points : 68
    Points
    68
    Par défaut
    Tout d'abord, le code que tu proposes ne contient aucun new, donc aucune allocation de mémoire : inutile donc de la libérer.

    Cependant, si dans ton constructeur tu allouais de la mémoire, par exemple pour ton char * (soit dit en passant, affecter "aa" à un pointeur ne signifie rien : un pointeur est une adresse), alors il faudrait penser à libérer celle-ci dans ton destructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    MaClasse:MaClasse()
    {
        unPointeurChar = new char;
    }
     
    MaClasse:~MaClasse()
    {
        delete unPointeurChar;
    }
    Quant à l'autre syntaxe que tu utilises, elle sert à libérer la mémoire occupée par des tableaux. D'après ce que j'ai compris, ton char * est en fait une chaîne de caractères. Dans ce cas, tu dois allouer de la mémoire pour plusieurs char, de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    MaClasse:MaClasse()
    {
        unPointeurChar = new char[10];
        unPointeurChar[0] = 'a';
        unPointeurChar[0] = 'a'; //La chaîne contient maintenant "aa", ainsi que des données
                                 //indéfinies dans les 8 caractères restants
    }
    Encore une fois, comme tu as alloué de la mémoire, tu dois la libérer. La syntaxe pour libérer la mémoire occupée par un tableau est la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    MaClasse:~MaClasse()
    {
        delete[] unPointeurChar;
    }
    Cependant, il me semble qu'il faudrait d'abord que tu apprennes la sémantique des pointeurs, ce qu'ils représentent, avant de t'occuper d'allocation et de désallocation.

  5. #5
    Membre éclairé Avatar de grabriel
    Inscrit en
    Septembre 2006
    Messages
    946
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 946
    Points : 730
    Points
    730
    Par défaut
    Oui j'ai oublié d'utiliser des new, en faite c'était plus pour le principe...

    Je débute et donc ma syntaxe est encore imparfaite, mais si je suis amené à utiliser des new à tout va (je faisait du java avant) je préfère savoir comment m'en dépatouiller. J'ai pas envie de prendre de mauvaise habitude.


    En règle générale, évite d'utiliser les new/delete...
    Faut faire comment pour créer de nouvelles classes??


    Merci pour vos réponses.

  6. #6
    Membre habitué
    Inscrit en
    Avril 2008
    Messages
    155
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 155
    Points : 158
    Points
    158
    Par défaut
    ben quand tu fais appel à un constructeur de la classe, un objet est créé!
    pas besoin de faire des new à droite et à gauche...

    la durée de vie d'un objet n'excède pas le fichier ou les parenthèse

    c'est bon à rappeler:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void main()
    {
      {
      maclasse objet;
      //ici au debugger tu pourras voir l'objet
      }
    //ici il n'existe plus ^^
    }

  7. #7
    Membre éclairé Avatar de grabriel
    Inscrit en
    Septembre 2006
    Messages
    946
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 946
    Points : 730
    Points
    730
    Par défaut
    Ok!

    Ca dû m'échappé.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 625
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 625
    Points : 30 674
    Points
    30 674
    Par défaut
    Salut,

    Oui, mais non...

    Oui car, de fait, si tu alloue dynamiquement de la mémoire pour un pointeur et que tu ne libère pas la mémoire, tu cours le risque d'une fuite mémoire, chaque fois que tu sors d'une portée dans laquelle tu déclare un pointeur.

    En effet, le langage estime que si "tu es suffisemment fou" pour vouloir gérer toi même la mémoire allouée à des objets, c'est que tu es "suffisemment compétant" pour savoir quand cette mémoire peut être libérée, et donc te charger de le faire au moment le plus opportun

    Mais non, le code que tu présente est très loin d'être correct.

    En effet, delete (ou delete[]) ne peut être invoqué que sur un pointeur alloué dynamiquement avec new (ou new[]).

    Il y a donc déjà un problème avec la tentative d'invoquer delete sur ton entier (car ce n'est pas un pointeur)... et même si "la (mal)chance" est avec toi sur le coup présent, du fait des particularités de l'usage de la virgule

    En outre, sur basse du code que tu fournis pour le constructeur, unPointeurDeChar ne pointe pas sur une adresse allouée dynamiquement mais... sur l'adresse d'un tableau constant créé de manière strictement statique

    Je parle bien sur de ce code ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    maClasse::maClasse(int unEntier, char* unPointeurChar)
    {
        unEntier = 3;
        unPointeurChar = "aa";
    }
    En effet, étant donné que tu passe des valeurs en arguments au constructeur, l'idéal est quand même de les utiliser pour initialiser les différents membres, de préférence sous la forme d'une liste d'initialisation.
    Le code prendrait alors la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    maClasse::maClasse(int unEntier, char* unPointeurChar): unEntier(unEntier), unPointeurChar(unPointeurChar)
    {
    }
    Pour rappel, le but d'un constructeur est d'initialiser les membres de ta classe afin de fournir un objet directement utilisable.

    Si donc tu fournis des arguments au constructeur, tu t'attend à ce que les valeurs des différents membres... correspondent à celle que tu a fournies en argument

    ainsi, tu ne comprendrait pas les valeurs des membres de obj créé à l'aide du code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char tab[5]="toto\0";
    MaClass obj(5,tab);
    puissent être... 3 et "aa" (re )

    Ensuite, il faut quand quand meme se rappeler que le fait de libérer la mémoire qui était allouée dynamiquement va automatiquement invalider tous les pointeurs qui pointent vers cette zone mémoire, ce qui risque de provoquer une erreur de segmentation lors de toute tentative d'acces à l'élément pointé par un pointeur se trouvant dans le cas.

    ainsi, le code ci-dessous présente les deux cas "peau de banane":
    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
    int main()
    {
        char* tab;
        char nondyn[5]="toto\0";
        /*...*/
        tab=new char[7];
        /*...
         * ce qui suit peut etre un test ou une boucle, et le problème est encore 
         * plus grave si c'est une boucle
         */
        {
            MaClass obj(7,tab);//obj est créé ici
            /*...*/
        }/* et détruit ici (avec appel du destructeur, et 
           * donc il y a invocation de delete) (à chaque passage s'il s'agit dune
           * boucle avec des problème dés le deuxième passage par ici
           */
        /*
         * tab pointe ici vers une adresse devenue tout à fait invalide, et toute 
         * tentative d'utilisation de tab se soldera par une cata
         */
        /*...*/
        char nondyn[5]="toto\0";
        {
            MaClasse obj(5,nondyn);//obj est créé ici
        }/*et détruit ici, avec invocation de delete... que l'on tente d'appliquer
          * à une adresse mémoire qui n'a pas été allouée dynamiquement
          */
        return 0;
    }
    Evidemment, il existe de nombreuses possibilités de contourner tous ces problèmes... Mais elles dépendent énormément de l'usage auquel tu destine ta classe

    Tout cela pour te faire comprendre que, Oui, le principal risque de l'allocation dynamique est la fuite mémoire mais, surtout, qu'une mauvaise gestion de la mémoire dynamique (induite entre autre par une mauvaise maitrise de la manière dont est utilisé l'objet) aura des conséquences encore bien plus désastreuses.

    C'est la raison pour laquelle:
    1. on insiste énormément sur les concepts de délégation des responsabilités (clairement identifier qui est responsable de l'allocation dynamique et qui est responsable de la libération de la mémoire, dans le cas)
    2. on préfère laisser autant que possible la gestion de la mémoire à des classes dont on sait qu'elle la gère correctement (entre autres toutes les classes fournies par la S(T)L)
    3. on choisi de travailler avec des pointeurs quand il n'y a pas d'autres choix (par exemple, pour certaines mises en oeuvre du polymorphisme, ou si un objet est sensé se contenir lui même)
    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 éclairé Avatar de grabriel
    Inscrit en
    Septembre 2006
    Messages
    946
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 946
    Points : 730
    Points
    730
    Par défaut
    Merci pour ces explications c'est plus claire mais ça reste encore floue...

    J'ai encore du boulot...

  10. #10
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Comprendre les différences entres les allocations admises par le c++ (dois je allouer sur la pile (statique) ou sur le tas (dynamique --> new, delete) ? ) est quel que chose de primordiale ?
    Un bon conseil : assures toi de bien avoir compris ce point avant de te lancer dans un projet important.

    Quelques ref:
    différence pile, tas
    gestion dynamique de la mémoire
    Linux > *

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

Discussions similaires

  1. Constructeur & Destructeur en UML
    Par fredhali2000 dans le forum UML
    Réponses: 5
    Dernier message: 31/03/2006, 19h31
  2. [Débutant] Constructeur d'une classe
    Par chennuo dans le forum Langage
    Réponses: 2
    Dernier message: 10/03/2006, 22h17
  3. [JUnit] [Test][Débutant] Constructeur privé
    Par Shabata dans le forum Tests et Performance
    Réponses: 2
    Dernier message: 12/01/2006, 15h45
  4. [D7] constructeur / destructeur
    Par raoulmania dans le forum Langage
    Réponses: 2
    Dernier message: 16/12/2005, 18h00
  5. [Débutant]Constructeur et new/delete
    Par Geolem dans le forum C++
    Réponses: 5
    Dernier message: 02/12/2005, 21h11

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