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 :

Problem avec Delete


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Septembre 2006
    Messages
    36
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Septembre 2006
    Messages : 36
    Points : 32
    Points
    32
    Par défaut Problem avec Delete
    Bonjour a tous
    je suis entrains de me remettre au C++, j'ai encore de bon reste mais j'ai perdu mes reflexs pour comprendre d'ou viennent les erreurs.

    En voici une que je comprend pas ^^:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Point *p3 = new Point(3,4);
     cout << "ADRESS OF P3: " << &p3 << " value: " << p3->getX() << endl ;
     delete p3; //not forget to free pointed memory
    cout << "ADRESS OF P3: " << &p3 << " value: " << p3->getX() << endl ;
    En sortie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int Point::getX()
    ADRESS OF P3: 0xbffff738 value: 3
    Point::~Point()
    int Point::getX()
    ADRESS OF P3: 0xbffff738 value: 3
    Ce que je comprend pas c'est que apres le delete de p3 je puisses encor acceder au valeur pointer par p3.

    Quelqu'un peut m'expliquer?



    Aussi, autre question getsion de memoire, si je creer une variable
    Point p = new point(1,2); je ne peux pas faire delete p.
    Est ce qu'il existe un moyen pour liberer la memoire quand je veus ou est ce que j'attend la fin du bloc?

    cordialement

    jason

  2. #2
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Alors déjà, p3 est déjà un pointeur. Donc le nom p3 coïncide avec l'adresse de l'objet. Quand tu écris p3->, cela veut juste dire :
    Bon, tu vas à l'adresse p3, tu regardes ce qu'y s'y trouve.
    Ensuite, si tu fais p3->GetX(), il va simplement aller appeler la fonction GetX() de ta classe Point avec comme objet courant ton objet résidant à l'adresse p3.
    Donc (1) : pas besoin de faire &p3.

    Ensuite, en C++, c'est soit :
    soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point* p = new Point(1.0, 2.0);
    mais ceci n'a aucun sens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point p = new Point(1.0, 2.0); // ça c'est en Java que ça passe
    Le premier, c'est une allocation statique : ton "p" sera détruit à la fin de la portée.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    std::cout << "On va rentrer dans la portée" << std::endl;
    {
      Point p(1.0, 2.0);
      std::cout << "p = (" << p.GetX() << "," << p.GetY() << ")" << std::endl;
    } // pouf, p n'existe plus !
    std::cout << "On est sorti de la portée, p n'existe plus !" << std::endl;
    Ce qui va se passer lorsque l'on arrive à la fin de la portée, c'est que le destructeur de la classe Point va être appelé et ainsi détruire ton objet p. Il ne sera plus valide. C'est pourquoi faire ceci est une mauvaise idée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Point* f()
    {
      Point p(1.0, 2.0);
      return &p;
    }
    Tu initialises un objet de type Point, et tu retournes son adresse. Or, une fois que la fonction sera terminée, le destructeur de p sera appelé.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Point* p_ptr = f();
    p_ptr->GetX(); // erreur de segmentation
    Donc tu assignes à p_ptr l'adresse d'un Point qui a été détruit. Ca ne pose pas de soucis... Jusqu'à ce que tu veuille faire quoique ce soit dessus. En effet, les cases mémoires qui étaient prises par ton Point ne sont plus valides, et ne contiennent plus ton Point, donc quand tu vas vouloir appeler GetX(), bam !

    C'est pour contourner les limitations de portée qu'on utilise encore les pointeurs, auquel cas pas de soucis ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Point* f()
    {
      return (new Point(1.0, 2.0));
    }
    // ...
    Point* p = f();
    p->GetX(); // pas de soucis
    Sauf qu'ici, c'est TOI (ou un collègue de travail ? ) qui va devoir te charger de détruire explicitement l'objet alloué dynamiquement (en C++ : new <=> allocation dynamique), via un delete. Tout ce que fait un delete, c'est détruire l'objet, i.e appeler son constructeur. Ca ne modifie pas l'adresse à laquelle pointait le pointeur, ou quoique ce soit.

    En espérant que ça t'aide à comprendre...

    PS : la FAQ regorge de pas mal de Q/Rs qui pourraient bien t'aider à mon avis.

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

    En fait, tu peux encore obtenir l'adresse de p parce que la variable qui représente le pointeur existe toujours: tu n'as libéré que la mémoire se trouvant à l'adresse pointée par p.

    Si tu peux toujours accéder à p->getX, et surtout avoir un résultat cohérent, ce n'est "que par chance", parce que:
    • L'adresse à laquelle se trouvait la valeur x de ton point n'a pas encore été réutilisée pour autre chose et les "crasses" qu'elle contient représentes toujours la dernière valeur représentée, à savoir... la valeur x de ton point
    • L'adresse à laquelle se trouvait le début des données de ton point n'a pas été réutilisé, et l'ensemble de la mémoire qui a servi pour représenter ton point contient encore les crasses de son utilisation précédente, et donc... ce qui permettait de représenter ton point.
    • Tu n'accède aux différents éléments de ce qui était ton point qu'en lecture (ici, pour obtenir la valeur de x)... Si tu décidais d'y accéder en écriture (par exemple pour modifier la valeur de x), tu armerais une véritable bombe à retardement dont tu n'aurais aucune idée du moment où elle "pètera"


    De plus, si tu venais à invoquer une deuxième fois delete sur p, tu enverrais systématiquement le compilateur cueillir les marguerites

    C'est la raison pour laquelle une "bonne habitude" à prendre est de systématiquement (il y a quelques exceptions pour lesquelles ce n'est pas forcément utile, mais pour lesquelles cela ne fait malgré tout pas de tord) assigner la valeur NULL à un pointeur une fois que tu a demandé la libération de la mémoire de l'adresse pointée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Aussi, autre question getsion de memoire, si je creer une variable
    point p = new point(1,2); je ne peux pas faire delete p.
    Tu ne peux déjà pas faire new point dans ce cas, car p n'est pas un pointeur...

    Si tu veux déclarer une variable normale de type p et l'initialiser directement de manière correcte, tu dois, simplement, invoquer le constructeur en lui fournissant les arguments requis sous la forme de:
    voire, si tu veux assigner un nouveau point à ta valeur, sous la forme de
    Il faut noter que l'utilisation de new en C++ n'a strictement rien à voir avec l'utilisation de new que l'on rencontre en java, par exemple...

    En C++, new ne s'applique que lorsqu'il s'agit d'assigner l'adresse d'une variable pour laquelle tu décide de prendre toi-même la responsabilité de sa durée de vie (c'est à dire que tu es seul responsable du moment où elle sera effectivement détruite) à un pointeur.

    Du fait des risques inhérents à cette manœuvre (risque de double libération de la mémoire ou de fuite mémoire, débordement d'index ( essayer de faire entrer N éléments dans un tableau dont la mémoire allouée dynamiquement ne permet que d'en contenir ... N-1), risque d'invalidation du pointeur avec delete, ...) il est largement recommandé de n'y recourir que lorsque l'on n'a vraiment pas le choix, et que l'on sait parfaitement ce que l'on fait.

    Lorsqu'il s'agit "simplement" de manipuler des collections d'objets identiques (ici des points), le C++ fournit de manière standard une série de conteneurs qui se chargent très bien de les contenir, allant de la pile au tableau associatif clé / valeur, en passant par le tableau dont les éléments sont contigus, la file, la liste et les arbres binaires (cf l'entrée de la FAQ quel conteneur choisir pour stocker mes objets?)

    La gestion dynamique de la mémoire n'est pas absente de ces conteneurs, mais elle est utilisée de manière tout à fait transparente en interne, ce qui t'évite d'avoir à y faire attention toi-même .

    Les cas dans lesquels tu auras recours à la gestion dynamique de la mémoire (appel à new / new[] et à delete / delete[]) se limiteront le plus souvent à des cas dans lesquelles tu dispose d'une hiérarchie de classe lorsque tu souhaite disposer d'objet ayant des comportements polymorphes, en faisant passer un objet comme étant... du type parent.

    De plus, il sera souvent intéressant d'utiliser des pointeurs intelligents (shared_ptr, scoped_ptr, unique_ptr, ...) afin de s'assurer que leur gestion se fasse sans heurts
    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

  4. #4
    Nouveau membre du Club
    Inscrit en
    Septembre 2006
    Messages
    36
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Septembre 2006
    Messages : 36
    Points : 32
    Points
    32
    Par défaut
    OKi doki
    merci pour vos reponses,
    c'est bien ce que je me rappelais de C++
    comme sa fait un moment que je tourne en Java et Objectif-C je suis entrains de faire plain de teste pour remettre les choses au claire.

    Je comprend que une varaible a porte locale sera:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point point_locale(1,2);
    et que pour gerer la memoire soit meme (allocation et deallocation manuel)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //Edit: oublie du * pour declarer un pointeur dsl
    Point *point_pointeur = new Point(3,4);
    cependant je voudrais vous corriger/soumettre sur ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point p = new Point(5,6);
    avec comme resultat a la compilation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Point::Point(int coordX,int coordY)
    Point::Point(Point *pointerPoint)
    Point::~Point()
    (je fais un cout dans chaque constructeur de ma classe point).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Point::Point(int coordX,int coordY){
        cout << "Point::Point(int coordX,int coordY)" << endl;
        this->x = coordX;
        this->y = coordY;
    }
     
    Point::Point(Point *pointerPoint){
        cout << "Point::Point(Point *pointerPoint)" << endl;
        this->x = pointerPoint->x;
        this->y = pointerPoint->y;
    }
    Enfin tout ce que je fais c'est de recopier les valeurs du pointeur dans le nouveau point.

    Mais comme vous l'avez dit c'est du Java, et surtout sa fait appel a 2 constructeur different pour rien.

    Merci pour vos reponses

    Ps:Alp: Je n'est pas de collegue de travail ^^ je suis entraint de me mettre a jour pour un entretiens de C++ (donc je croise les doigts pour que bientot j'aurais des collegues lol)

  5. #5
    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
    Lorsque tu veux déclarer un pointeur, il faut une étoile " * " entre le type et le nom de l'objet...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point p = new Point(3,4);
    ne compilera pas... c'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point * p =new point(3,4); //remarque l'étoile '*' entre Point et p
    qu'il faut écrire
    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

  6. #6
    Membre confirmé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Points : 546
    Points
    546
    Par défaut
    Bonjour,
    Citation Envoyé par anarkia Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point p = new Point(5,6);
    avec comme resultat a la compilation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Point::Point(int coordX,int coordY)
    Point::Point(Point *pointerPoint)
    Point::~Point()
    oui mais cela n'est possible que parce que tu as déclaré le constructeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point::Point(Point *pointerPoint)
    qui n'est pas un constructeur par copie (du point de vue du c++) et est même plutôt déconseillé. Dans le même ordre d'idée il est possible d'écrire pour permettre (attention code affreux )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point p = new int(5); // avec fuite mémoire à la clé
    Le constructeur par copie s'écrit (voir Faq)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Point::Point(const Point & OtherPoint){
        cout << "Point::Point(const Point & OtherPoint)" << endl;
        x = OtherPoint.x;
        y = OtherPoint.y;
    }
    Exemple d'usage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Point p1(1.0, 2.0);
    Point * p2 = new Point(p1);
    Point p3 = new Point(*p2);
    Point * p4 = new Point(*p2);
    delete p2;
    delete p4;
    Remarque :
    une différence fondamentale à comprendre en C++ par rapport à d'autres langages est la manière dont sont considérés les objets.
    Si en Java, les objets ne peuvent être manipulés que par "référence" (au sens Java ~> pointeurs C++, en un peu plus protégé),
    et si en C# et Delphi, les objets peuvent être de type valeur ou "référence" selon le mot clé employé (class/struct, class/record) avec les restrictions inhérentes au type,
    le C++ utilise un seul format de définition des objets (class ou struct), mais selon les constructeurs/opérateurs/fonctions définies et/ou interdits (par mise en membre privé) ces objets sont à utiliser plus par valeur ou par pointeur.

  7. #7
    Nouveau membre du Club
    Inscrit en
    Septembre 2006
    Messages
    36
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Septembre 2006
    Messages : 36
    Points : 32
    Points
    32
    Par défaut
    Merci pour vos reponses
    effectivement j'en etait arriver a plus ou moin la bonne conclusion que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Point p = new Point();
    devenait possible seulement a cause de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Point::Point(Point *p_point);
    c'est comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Point p1, p2, p3;
    p3 = p1 + p2;
    Ceci est possible que si l'operateur + a etait surdefinie.


    Comme je l'ais dit plus haut, je suis juste entrain de me remettre au C++ et le meilleur moyen c'est de se mettre au clavier et d'essayer tous ce qui passe par la tete.

    En tout cas merci, maintenant j'ai compris.

    Bonne continuation.

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

Discussions similaires

  1. probleme AVEC delete
    Par norais dans le forum Langage
    Réponses: 1
    Dernier message: 28/08/2012, 00h35
  2. Probleme avec "delete en ADO
    Par nguhv dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 10/04/2007, 08h26
  3. Probleme avec delete[]
    Par anisjemmali dans le forum C++
    Réponses: 4
    Dernier message: 28/03/2007, 17h46
  4. Probleme avec delete
    Par edogawa dans le forum Hibernate
    Réponses: 4
    Dernier message: 04/09/2006, 14h39
  5. [ EJB ] [JBoss ] [ XDoclet ] probleme avec cascade-delete
    Par Houbbba dans le forum Wildfly/JBoss
    Réponses: 4
    Dernier message: 03/05/2006, 10h05

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