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 :

Différence entre delete et delete []


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut Différence entre delete et delete []
    Bonjour

    On sait tous que quand on fait une allocation dynamique,
    Il faut désallouer avec delete [] et non delete. Alors moi, j'ai essayé en débug de voir ce qu'il se passe avec visual studio. J'ai tout d'abord linké le programme avec la version release de la CRT. Ensuite, j'ai fait ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int *o=new int[100];
    for(int j=0;j<100;j++)
    	o[j]=3;
    delete o;
    Ce qui est pas bon. Quand j'alloue le tableau de 100 int de valeur 3, je vois ceci:
    Nom : 1.JPG
Affichages : 170
Taille : 73,6 Ko
    On voit bien le tableau avec les 100 int. Ensuite, quand je fais le delete, je vois que tous les int sont désalloués. Moi, je m'attendais à ce que seule la première adresse, celle pointée par o soit désallouée.
    Une fois le delete executée, voila ce que je vois:
    Nom : 2.JPG
Affichages : 165
Taille : 69,1 Ko

    Ensuite, j'ai fait le truc correct:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int *o=new int[100];
    for(int j=0;j<100;j++)
    	o[j]=3;
     
    delete [] o;
    Et dans la première image, on voit l'allocation, et dans la deuxième, on voit la désallocation.

    Nom : 3.JPG
Affichages : 155
Taille : 87,3 Ko


    Nom : 4.JPG
Affichages : 146
Taille : 78,0 Ko

    On voit qu'il n'y a aucune différence. Je ne comprends pas. Comment faire pour voir la différence entre delete et delete[] ?

    Merci

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Par défaut
    Hello

    A mon avis, c'est juste une optimisation qui détecte ton erreur et la corrige.

  3. #3
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2011
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mars 2011
    Messages : 59
    Par défaut
    salut ,

    sur un type simple (ADT) tu ne verras pas la différence, car dans les deux cas ça ne fait que libéréer la mémoire allouée

    par contre sur un type avec constructeur/destructeur là il y a différence

    dans delete : seul le premier destructeur est appelé ensuite la mémoire est libérée

    dans delete[] : les destructeurs sont appelée et la mémoire libérée

    Cdt

  4. #4
    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
    détail d'implémentation du compilateur. Cela n'a que peu de sens de regarder.
    Tu invoques un comportement non défini. Donc le compilateur peut faire comme si de rien était, générer une exception, planter ou faire le café. Je ne vois vraiment pas l'intérêt de cette question

  5. #5
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut
    sur un type simple (ADT) tu ne verras pas la différence, car dans les deux cas ça ne fait que libéréer la mémoire allouée
    J'ai testé avec une classe contenant un int et un double. Pas vu de différence entre delete et delete [].

    Tu invoques un comportement non défini. Donc le compilateur peut faire comme si de rien était, générer une exception, planter ou faire le café. Je ne vois vraiment pas l'intérêt de cette question
    Hé oui, mais c'est bien facile de dire que l'on provoque une exception, on dit ce que raconte la norme.
    Encore faut il le démontrer et/ou l'expérimenter. C'est comme ca que je comprends.

  6. #6
    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 deubelte Voir le message
    Hé oui, mais c'est bien facile de dire que l'on provoque une exception, on dit ce que raconte la norme.
    Encore faut il le démontrer et/ou l'expérimenter. C'est comme ca que je comprends.
    J'ai pas dit que ça provoque une exception. J'ai dit que tu évoques un comportement indéterminé (l'exception pouvant être une réponse comme une autre). Pour le reformuler autrement, tu écris un code faux et buggé et tu regardes comment ça marche ... au cas où quoi ? Au cas où ça tomberait en marche ? Et quelle(s) serai(en)t ta(tes) conclusion(s) alors ?? Aucune car tu invoques un comportement indéterminé. Tu ne peux donc rien conclure sur ce comportement.

  7. #7
    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 kessoufi Voir le message
    salut ,

    sur un type simple (ADT) tu ne verras pas la différence, car dans les deux cas ça ne fait que libéréer la mémoire allouée
    ADT, pour moi c'est Abstract Data Type. Peut-être pensais-tu à POD (Plain Old Data) ? En fait, dans l'implémentation de Microsoft Visual C++ 2010 en mode débug et avec les options de compilations (XXX) cela a plus à voir avec la nécessité ou non d'appeler un constructeur ou un destructeur. (la présence d'un destructeur rend en C++98 un type non POD mais pas la seule présence d'un constructeur).
    Pour reprendre, new/new[] fait deux choses : allouer un espace mémoire suffisant et appeler le constructeur qu'il faut. delete/delete[] à l'inverse appelle les destructeurs nécessaires et libère la mémoire.
    Un new int[]/delete [] ou un new int[]/delete semblent identique car j'imagine que l'implémentation la plus facile pour un compilateur est d'appeler juste la fonction d'allocation et de libération de la mémoire. MAIS CA RESTE UN COMPORTEMENT INDETERMINE

  8. #8
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut
    Yo,
    j'ai essayé un nouveau truc, avec cette classe non POD.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class  S{
    public:
    	S(){};
    	S(int y,std::string d):o(y),e(d){};
     private:
    	int o;
    	std::string e; 
    };
    quand je fais ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    S* o=new S[100];
    for(int j=0;j<100;j++)
    	o[j]=S(1,"ee");
    delete [] o;
    ça marche, alors si je fais delete o;

    ca me renvoie comme erreur:

    Windows has triggered a breakpoint in cac.exe.

    This may be due to a corruption of the heap, which indicates a bug in cac.exe or any of the DLLs it has loaded.

    This may also be due to the user pressing F12 while cac.exe has focus.

    The output window may have more diagnostic information.

  9. #9
    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 deubelte Voir le message
    ...



    Et moi, et moi, quand je fais ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
     int bug = 0;
     bug = 1/bug;
    return 0;
    }
    Ben j'ai un bug (ou pas car là aussi c'est un comportement indéterminé)

  10. #10
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2011
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mars 2011
    Messages : 59
    Par défaut
    ça me fait pareil avec cette classe ( ça déclenche un breakpoint) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    struct a
    {
        int i;
        ~a() {}
    };
    mais lorsque je commente le destructeur ça passe (comme pour un int*), et pourtant ce n'est pas du POD,

  11. #11
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut
    En fait, je me suis posé cette question, car dans le livre de Sutter, exceptionnal C++, page 144, on a:

    Consider the following code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class B
    {
    virtual ~B();
    void operator delete (void*,size_t) throw();
    void operator[] delete (void*,size_t) throw();
    void f(void*,size_t) throw();
    };
    class D: public B
    {
    public:
    void operator delete (void*)throw();
    void operator delete[] (void*)throw();
    };
    Or, dans le livre de Scott Meyers, il nous dit qu'il ne faut jamais traiter des tableau de manière polymorphe.
    (Never treat array polymorphically). mais dans le code ci-dessus, cela laisse penser qu'on va utiliser des tableaux d'objets dérivés.

    Il y a comme un petit problème, ou du moins, une incohérence dans la question de Sutter.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Tu remarqueras que tes opérateurs delete ne sont pas virtuels, ce qui implique que... leur utilisation ne sera pas polymorphique : tu te trouve dans une situation dans laquelle l'operateur delete de D cache celui de B, pour autant que tu ait la certitude de travailler avec un pointeur sur D.

    !!! si tu appelle delete sur un pointeur sur B qui pointe vers un objet de type D, ce sera l'operateur B::delete qui sera appelé, et non l'opérateur D::delete, avec tous les dangers que cela peut représenter !!!
    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

  13. #13
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    618
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mars 2011
    Messages : 618
    Par défaut
    Je croyais que l'operator delete ne pouvait être virtuel, m'aurait-on mentis ?

  14. #14
    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 koala01 Voir le message
    Tu remarqueras que tes opérateurs delete ne sont pas virtuels, ce qui implique que... leur utilisation ne sera pas polymorphique : tu te trouve dans une situation dans laquelle l'operateur delete de D cache celui de B, pour autant que tu ait la certitude de travailler avec un pointeur sur D.

    !!! si tu appelle delete sur un pointeur sur B qui pointe vers un objet de type D, ce sera l'operateur B::delete qui sera appelé, et non l'opérateur D::delete, avec tous les dangers que cela peut représenter !!!
    Non, non.

    Les opérateurs new et delete d'une classe sont toujours static même s'ils ne sont pas explicitement définis comme tel (de toute façon à quelle instance s'appliquerait un new??). Ils ne peuvent donc être virtuels.

    delete p utilise le type statique de p pour savoir si l'appel est valide et utilise l'opérateur delete du type dynamique de p si le destructeur du type statique est virtuel.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct B {
    virtual ˜B();
    void operator delete(void*, size_t);
    };
    struct D : B {
    void operator delete(void*);
    };
    void f()
    {
    B* bp = new D;
    delete bp; //1: uses D::operator delete(void*)
    }
    Sinon, c'est indéterminé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct B {
    ˜B();
    void operator delete(void*, size_t);
    };
    struct D : B {
    void operator delete(void*);
    };
    void f()
    {
    B* bp = new D;
    delete bp; //undefined behaviour
    }
    delete []p sur un type statique et dynamique différent est un comportement indéterminé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    struct B {
    virtual ˜B();
    void operator delete[](void*, size_t);
    };
    struct D : B {
    void operator delete[](void*, size_t);
    };
    void f(int i)
    {
    D* dp = new D[i];
    delete [] dp; // uses D::operator delete[](void*, size_t)
    B* bp = new D[i];
    delete[] bp; // undefined behavior
    }

  15. #15
    screetch
    Invité(e)
    Par défaut
    pour être précis, delete appelle le destructeur de la classe (dynamique donc) avec un paramètre caché, 1
    ce paramètre dit "libère la mémoire après l'appel"
    le destructeur appelle les destructeurs des classes parentes avec le paramètre 0, puis libère la mémoire avec operator delete qui correspond le mieux (celui de la classe si possible, sinon celui du parent, etc etc)
    comme c'est le destructeur qui libère la mémoire, il appelle toujours le delete correct.


    En gros lorsque tu fais delete a; il se passe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    push 1
    call vtable(a)->0
    et le destructeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ...blablabla destruction
    push 0
    call parentdestructor
    if parametrecaché
      call operator delete

  16. #16
    screetch
    Invité(e)
    Par défaut
    (encore une fois c'est du détail d'imlémentation et on est pas sensé savoir, hein, c'est juste pour expliquer comemnt ca marche et c'est pas par magie)

  17. #17
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut
    Merci pour toutes vos réponses, mais ca m'enmèle un peu. Doit on utiliser ou non un tableau sur des objets dynamiques?


    Dans les classes données par Sutter, estce que vous pouver me donner des exemples d'implémentation des delete et des new qui sont déclarés?

    merci

Discussions similaires

  1. Différence entre TRUNCATE et DELETE ?
    Par HRS dans le forum SQL
    Réponses: 18
    Dernier message: 12/08/2011, 16h07
  2. différence entre delete et delete[]
    Par deubelte dans le forum C++
    Réponses: 7
    Dernier message: 25/02/2009, 03h30
  3. [BDE][TTABLE] différence entre EMPTY et DELETE
    Par cal dans le forum Bases de données
    Réponses: 1
    Dernier message: 15/02/2008, 08h04
  4. Différences entre delete table et delete from table
    Par pegase06 dans le forum Administration
    Réponses: 3
    Dernier message: 16/02/2007, 15h25
  5. Réponses: 3
    Dernier message: 07/05/2002, 16h06

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