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 :

Access Violation sur un delete


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    lkjlgj
    Inscrit en
    Février 2007
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Angola

    Informations professionnelles :
    Activité : lkjlgj

    Informations forums :
    Inscription : Février 2007
    Messages : 255
    Par défaut Access Violation sur un delete
    Bonjour,

    Je cherche à comprendre pourquoi un delete qui porte sur un tableau de longs de taille définie et invariable plante alors que je peux jusqu'à ce point effectuer toutes les opérations de lecture et écriture dans ce tableau sans le moindre problème.

    Sans m'étendre sur les détails, voici une idée du code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    long *Tablo = new long [100];
     
    for(long i=0; i<100; i++) Tablo[i]=i;
     
    if(Tablo)	
    {
    delete[] Tablo;    // Et là, ça plante : "Access Violation"
    Tablo=NULL;
    }

  2. #2
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Est-ce que ce code plante? Je ne pense pas.

    Que l'équivalent de ce code, noyé au milieu de plusieurs milliers d'autres lignes plante, c'est possible.

    Il suffit simplement qu'il y ait un buffer overflow quelque part ou que Tablo ait été modifié par erreur (Tablo++), et voila...

    Connais-tu std::vector?
    http://cpp.developpez.com/faq/cpp/?page=STL#STL_vector

  3. #3
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    En C++, on a maintenant des outils pour déléguer la gestion pure de la mémoire à des entités (classes en fait). Ca s'appelle le RAII.
    Les tableaux sont dans 99% des cas remplacer par un vector (cf remarque d'Aurélien). Les 1% restant, on utilise boost::array.
    En ce qui concerne les pointeurs, on a aussi tout intérêt à les "donner" à une classe qui les gère, comme boost::shared_ptr.

  4. #4
    Membre éclairé
    Profil pro
    lkjlgj
    Inscrit en
    Février 2007
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Angola

    Informations professionnelles :
    Activité : lkjlgj

    Informations forums :
    Inscription : Février 2007
    Messages : 255
    Par défaut
    Ouais...

    Devant mon impossibilité de trouver pourquoi le delete plante, j'avais déjà pensé à vector que j'utilise un peu (dans d'autres programmes).
    C'est juste que ça me turlupine de pas comprendre pourquoi le delete plante alors que je peux je lire / écrire partout dans cette zone mémoire apparemment bien délimitée. Si moi et l'ordinateur on est d'accord sur l'attribution des 100 cases depuis le début, alors pourquoi le delete (qui doit avoir gardé trace du new long [100]) ne marche-t-il-pas ?

    Je crois comprendre la théorie du Tablo++ fautif, mais en vérifiant l'adresse de Tablo, au début et à la fin du programme, je constate qu'elle est la même, donc il n'y a pas eu de déplacement erroné de Tablo. Alors quele peut être la cause du problème ?

    En tout état de cause, je passe à Vector...

  5. #5
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Y'a une explication, mais le code que nous montre est correct. Peut-être qu'avec un peu plus de code on verrait d'où vient le problème...

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

    On peut fortement envisager le fait qu'il y ait quelque chose entre la partie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(long i=0; i<100; i++) Tablo[i]=i;
    et la partie
    Et il y a fort à parier (bien que n'ayant pas vu le code) qu'il y aura l'un ou l'autre appel de fonction

    Si l'une de ces fonctions appelées (ou pire, l'une des fonctions éventuellement appelées par une des fonctions qui se trouve entre les deux parties de code) appelle delete[] sur Tablo (ou sur le nom qu'il obtient lors du passage par argument), bien que *sensé* représenter une adresse valide, ce n'est peut être plus le cas.

    A ce moment là, toute tentative de refaire un delete[] sur cette adresse - devenue invalide - occasionnera systématiquement une violation d'accès

    Si donc, tu as d'autres fonctions qui peuvent vouloir libérer la mémoire de ce pointeur, il est préférable de fournir un pointeur de pointeur comme argument, de libérer la mémoire sur ce qui est pointé par cet argument et de le faire pointer sur NULL.

    Cela permettra, au sortir de la fonction, que Tablo valle NULL et donc que le test ne provoque pas cette tentative de nouvelle libération de la mémoire

    Ceci dit, on ne peut que t'inciter à envisager l'utilisation des std::vector<un type> aussi souvent que possible
    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 éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Oui ou simplement faire un Tablo[100] = x; quelque part sans s'en apercevoir.

  8. #8
    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
    Citation Envoyé par NiamorH Voir le message
    Oui ou simplement faire un Tablo[100] = x; quelque part sans s'en apercevoir.
    ou de faire un tablo++, comme l'a dit Aurelien...

    C'est la raison pour laquelle il faudrait que l'on puisse disposer du code minimum compilable reproduisant l'erreur.

    les 6 lignes de code sont, a priori, justes (quoi que, personnellement, je mettrait la ligne Tablo=NULL; hors du test)... Et si "quelque chose foire", c'est donc ailleurs que cela survient
    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
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 966
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 966
    Par défaut
    Hio,
    Citation Envoyé par koala01 Voir le message
    quoi que, personnellement, je mettrait la ligne Tablo=NULL; hors du test
    Pourquoi ?

    Il est parfaitement à sa place, juste après le delete, et si le test échoue, alors Tablo est déjà NULL, donc inutile de lui affecter cette valeur hors du test réussi.

  10. #10
    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
    Citation Envoyé par droggo Voir le message
    Il est parfaitement à sa place, juste après le delete, et si le test échoue, alors Tablo est déjà NULL, donc inutile de lui affecter cette valeur hors du test réussi.
    Mais d'un autre coté cela permet de s'assuré que Tablo soit d'office à NULL en sortie de fonction...

    Il n'est pas plus mal placé à un endroit qu'un autre, je te l'accorde, et c'est donc une pure histoire de gout
    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

  11. #11
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 966
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 966
    Par défaut
    Kio,
    Citation Envoyé par koala01 Voir le message
    Mais d'un autre coté cela permet de s'assuré que Tablo soit d'office à NULL en sortie de fonction...

    Il n'est pas plus mal placé à un endroit qu'un autre, je te l'accorde, et c'est donc une pure histoire de gout
    Tel qu'il est mis, il assure parfaitement de sortir de la fonction avec une valeur NULL.
    Pourquoi vouloir détacher la mise à NULL du delete, sa place logique ?

    Si tu le sors du test, tu ne fais que mettre une valeur NULL dans une variable dont c'est déjà la valeur.

  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
    En fait, c'est surtout que le test if(Tablo) n'a déjà normalement aucune raison d'être...

    En effet, delete - et delete[]- sont garantis contre les problèmes au cas où l'on tenterait de les appliquer sur NULL.

    Et comme if(Tablo) ne garanti aucunement que la mémoire pointée soit correcte si Tablo ne vaut pas NULL... il en devient un test inutile

    Et c'est la raison pour laquelle, si un pointeur doit devenir invalide en sortie d'une fonction, je préfère l'invalider de manière strictement inconditionnelle
    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

Discussions similaires

  1. Access violation sur une string
    Par Nekkro dans le forum C++
    Réponses: 11
    Dernier message: 23/01/2012, 08h41
  2. Access violation sur dsnap140.bpl
    Par Ben_Le_Cool dans le forum Langage
    Réponses: 4
    Dernier message: 29/07/2011, 20h06
  3. Réponses: 5
    Dernier message: 27/01/2009, 10h58
  4. Access violation sur un new
    Par cedekasme dans le forum C++Builder
    Réponses: 16
    Dernier message: 23/01/2007, 14h32
  5. Réponses: 7
    Dernier message: 23/05/2006, 11h32

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