Différence entre delete p et p = NULL - C++ - Programmation
Marsh Posté le 09-04-2006 à 16:48:20
delete p libère la mémoire alors que p = NULL indique simplement que le pointeur p est réaffecté.
En général on devrait (je suppose, mais c'est ce que je ferais en C) faire
Code :
|
Marsh Posté le 09-04-2006 à 21:48:52
en fait, en C++, delete mets la valeur détruite a NULL par défaut je crois.... mais fodrais vérifier...
Marsh Posté le 09-04-2006 à 21:53:09
karminator98 a écrit : en fait, en C++, delete mets la valeur détruite a NULL par défaut je crois.... mais fodrais vérifier... |
tu as tord
Marsh Posté le 09-04-2006 à 22:00:35
Moi j'avais compris que delete supprimai l'addresse mais pas ce vers quoi il pointe, et que NULL attribuait aucune addresse au pointeur, donc je ne voyais pas la difference.
Marsh Posté le 09-04-2006 à 22:05:31
En y réfléchissant un peu, delete fait peut-être beaucoup plus que libérer la mémoire, il y a surement appel au destructeur de classe, mais comme je ne connais rien du tout à C++...
Marsh Posté le 09-04-2006 à 23:03:49
Juste pour dire faire
delete p;
p = NULL;
ne sert a rien car quand tu fait delete p, p = NULL, faite le teste mais si vous faite
p = NULL;
delete p;
il y aura une erreur car p est deja NULL donc on ne peut pas faire delete p.
Marsh Posté le 09-04-2006 à 23:11:58
Non, tout faux.
1- delete p; // n'assigne pas p à 0.
2- delete 0; // est garanti d'etre sans effets.
Marsh Posté le 09-04-2006 à 23:19:12
> ne sert a rien car quand tu fait delete p, p = NULL, faite le teste
p = NULL après un delete est pas standard. Si tu désactive le debug, ou active l'optimisation, ça ne fonctionne plus.
Si tu écris les lignes ci-dessus en dehors d'une boucle, tu te prépare un segfault.
Marsh Posté le 09-04-2006 à 23:39:30
Perso, je mets toujours les pointeurs libérés par delete à 0 pour détecter un mauvais usage plus tard. Parce que si le pointeur venait à être supprimé une nouvelle fois plus tard, je ne suis pas certain de trouver l'orgine du problème rapidement quoique VC m'aura probablement averti
Marsh Posté le 10-04-2006 à 00:07:12
Comme l'indiquait ++fab:
Citation : |
Tu ne détectera pas les erreurs de destruction en mettant systématiquement les pointeurs à 0. Ça produit une illusion de sécurité, et le bogue peut apparaître silencieusement à la 10 000ème ligne de code, avec des effets de bord conséquents.
Si tu laisse les pointeurs supprimés tels quels, une destruction supplémentaire produira une violation de mémoire à l'execution, que tu peut alors diagnostiquer avec un deboggueur.
L'exeption est dans une boucle, où un pointeur sert plusieurs fois, et il est pratique de le mettre à 0 pour indiquer qu'il ne pointe pas sur un objet valide. Dans ce cas un commentaire dans la déclaration du pointeur est necessaire pour indiquer les conditions pour lesquels il est valide ou non.
Marsh Posté le 10-04-2006 à 00:48:52
nargy a écrit : Tu ne détectera pas les erreurs de destruction en mettant systématiquement les pointeurs à 0. Ça produit une illusion de sécurité, et le bogue peut apparaître silencieusement à la 10 000ème ligne de code, avec des effets de bord conséquents. |
Assigner un pointeur à 0 après un appel à l'operateur delete([]), c'est s'assurer qu'il n'y aura pas de "double delete". J'y vois la un peu plus qu'une illusion de sécurité.
nargy a écrit : L'exeption est dans une boucle, où un pointeur sert plusieurs fois, et il est pratique de le mettre à 0 pour indiquer qu'il ne pointe pas sur un objet valide. |
Je ne vois pas en quoi une boucle constitue une exception. Et une exception à quoi ?
nargy a écrit : Dans ce cas un commentaire dans la déclaration du pointeur est necessaire pour indiquer les conditions pour lesquels il est valide ou non. |
Un pointeur est garanti invalide s'il est null, c'est la seule information fiable sur laquelle on peut se baser.
Marsh Posté le 10-04-2006 à 01:20:47
Ouais, je ne me suis peut être mal exprimé.
Tu peut t'assurer qu'il n'y a pas de double delete, mais ça ne t'assure pas qu'il n'y a pas de bug de conception.
C'est dans une boucle que tu utilise un pointeur nul, par nécessité:
- boucle simple:
for(pointeur* p=debut;p;p=p->next)...
- boucle plus complexe:
for(int i=0;i<tab.count();i++)
if(rand()%2) { delete tab[i].pointeur; tab[i].pointeur=0; }
Dans tout ces cas il vaut mieux indiquer en commentaire les conditions d'arrêt des boucle, ou de validité du pointeur, lors de sa déclaration:
struct avecpointeur
{ pointeur* pointeur; /* peut être nul quand blabla */ }
Ton algorithme n'est pas garanti valide parceque tu utilise un pointeur nul. Par contre un pointeur nul peut cacher un bug de l'algorithme. (exemple: liste chaînée qui fait des pertes de mémoire)
Marsh Posté le 10-04-2006 à 12:17:36
J'ai une question : en C la norme n'assure pas que NULL est identique à 0, donc il ne faut pas écrire p = 0 à la place de p = NULL (même si beaucoup de gens le font).
Qu'en est-il en C++ ?
Marsh Posté le 10-04-2006 à 12:38:23
ReplyMarsh Posté le 10-04-2006 à 12:40:43
ReplyMarsh Posté le 10-04-2006 à 12:46:28
quand tu affectes une valeur d'un type à une variable d'un autre type une convertion a lieu
ce que la norme assure en C et en C++ c'est que 0 typé pointeur vaut NULL, comme le C est assez permissif à la base (on peut appeler une fonction sans en donner le protoptype) le standard définie une constante NULL qui vaut en général ((void*)0)
Marsh Posté le 10-04-2006 à 12:55:52
En pratique, je ne connais aucune processeur pour lequel un pointeur NULL différent de 0 produit de meilleures optimisations. Y en a-t-il?
Marsh Posté le 10-04-2006 à 12:56:44
nargy a écrit : Tu peut t'assurer qu'il n'y a pas de double delete, mais ça ne t'assure pas qu'il n'y a pas de bug de conception. |
En même temps (en C) :
strcpy(pointeur invalide,"machin" ) => dans un programme de quelques dizaines de milliers de lignes, tu peux t'amuser avant de trouver ce bug-là, parce que ça produit des comportements aléatoires... parfois dans des parties du programme qui n'ont rien à voir.
Alors que :
strcpy(NULL, "machin" ) => segfault
Pour moi, mettre à NULL un pointeur que l'on vient de libérer, c'est loin d'être une sécurité négligeable.
Marsh Posté le 10-04-2006 à 13:59:35
nargy a écrit : En pratique, je ne connais aucune processeur pour lequel un pointeur NULL différent de 0 produit de meilleures optimisations. Y en a-t-il? |
le C et le C++ se veulent portable et il n'y a aucune raison d'imposer l'adresse 0 comme adresse nulle, par contre 0 est la seule adresse litterale portable
Marsh Posté le 10-04-2006 à 14:11:43
En fait un pointeur nul est valide pour certaines fonctions (genre delete, free, realloc). Nul indique seulement qu'il est vide.
Pour avoir véritablement un pointeur invalide, le mettre à (far)nul-1 le rendrait invalide sur la plupart des systèmes.
Enfin, je pense que ça mérite réflexion...
Marsh Posté le 10-04-2006 à 14:16:49
Cela n'aurait pas grand intérêt dans la mesure où il n'y aurait pas d'amélioration dans la détection d'erreur.
Et qu'on s'éloignerait inutilement des standards, vu qu'en C (et en C++), on s'attend à ce qu'un pointeur non initialisé ait pour valeur NULL, et pas autre chose.
Marsh Posté le 10-04-2006 à 15:43:44
> en C (et en C++), on s'attend à ce qu'un pointeur non initialisé ait pour valeur NULL, et pas autre chose.
hein?
Marsh Posté le 10-04-2006 à 16:04:35
s/non initialisé/invalide/g
Lorsque je teste un pointeur, peu importe la manière dont je l'ai obtenu, s'il est différent de NULL alors il est valide... C'est en tout cas le comportement attendu.
Marsh Posté le 10-04-2006 à 16:09:53
Oui, c'est comme ça que ça été conçu: un pointeur NULL est invalide.
Mais ce n'est pas comme ça que c'est utilisé, bien souvent celà signifie <<pointeur vide>>.
Aussi, il me semble qu'il manque toujours un <<pointeur invalide>>, un vrai de vrai.
Un peu comme les réels, un NaN strict, pas un +-Inf ou un NaN silencieux.
Marsh Posté le 10-04-2006 à 16:29:21
mais cette valeur c'est NULL
apres on s'en fout de comment c'est interpreté du moment que ce n'est pas considé comme une adresse valide
Marsh Posté le 10-04-2006 à 16:31:38
nargy a écrit : Oui, c'est comme ça que ça été conçu: un pointeur NULL est invalide. |
C'est quoi un "pointeur vide" ?
Marsh Posté le 10-04-2006 à 16:37:47
pointeur vide:
free(p); // valide
pointeur invalide:
free(p); // erreur
Marsh Posté le 10-04-2006 à 16:48:47
et ?
free test si le pointeur est à NULL, tant mieux, et il y en a beaucoup des fonctions qui tiennent compte de NULL
un pointeur NULL est invalide
Marsh Posté le 10-04-2006 à 17:05:05
skelter a écrit : mais cette valeur c'est NULL |
D'accord avec ça. Remplacer NULL par 0 revient à casser le lien sémantique
(cf couplage sémantique page 110 de "Tout sur le code - 2nd Edition de Steve McConnell" )
Au passage, tu avais raison harko : c'est vraiment un bouquin à avoir chez soi.
Merci.
Marsh Posté le 10-04-2006 à 17:28:11
> Remplacer NULL par 0 revient à casser le lien sémantique
ha, voilà ce que je cherchais à exprimer, free(NULL) n'a pas de sens: <<libérer une zone mémoire qui n'est pas valide>> et devrait provoquer une erreur.
Au contraire, free(0) <<libérer une zone mémoire qui est déjà vide>> ne produit pas d'erreur.
Enfin, bref, Invalid NULL pointer in neuron #334.
PS: tient, au fait, dans un ordinateur de shroedinger il y a des pointeurs paradoxaux.
Marsh Posté le 10-04-2006 à 17:37:10
free(0) et free(NULL) c'est la meme chose (en C, si le compilateur dispose du prototype lui indiquant que free prend un parametre de type void*)
Citation : <<libérer une zone mémoire qui est déjà vide>> |
ca ne veut rien dire (de meme un "pointeur vide" n'a aucun sens, un pointeur contient une adresse), et si tu sous entends "une zone mémoire déjà liberer" alors c'est impossible puisque NULL est invalide
en fait t'as toujours pas compris ??
Marsh Posté le 10-04-2006 à 18:14:39
> en fait t'as toujours pas compris ??
ben ce que j'ai compris:
- NULL est un pointeur invalide
- on peut libérer une zone de mémoire invalide avec free(NULL)
Ce qui me semble plus logique, plus complet, moins sujet à bugs:
- NULL ne pointe vers aucun objet (zone mémoire vide, taille zéro, kedaldedan)
- INVALID pointe vers une zone mémoire invalide (ya un bug)
- free(NULL): ne rien faire puisqu'il n'y a pas d'objet à libérer
- free(INVALID): lancer une erreur (signal, throw,...)
- NULL==0, INVALID==-1 me semble un bon choix pour la plupart des systèmes,
- NULL reste utilisé pour les structures de données (listes, arbres, graphes, ..),
- INVALID est utilisé pour la gestion mémoire (manque de mémoire, fuite par ci, bug par là).
Ce que je constate: NULL est utilisé à la fois comme NULL (aucun objet) et INVALID (objet invalide).
Tout ça c'est accessoire, tu peut toujours ajouter un booléen.
Marsh Posté le 10-04-2006 à 18:46:13
Citation : NULL est un pointeur invalide |
oui
Citation : on peut libérer une zone de mémoire invalide avec free(NULL) |
free(NULL) à un comportement définie, en l'occurence il ne fait rien
Citation : - NULL ne pointe vers aucun objet (zone mémoire vide, taille zéro, kedaldedan) |
un pointeur contient une adresse (apres sémantiquement tu peux dir que ca pointe vers ce vers quoi tu prétends que ca pointe suivant le typage), si tu lui affectes une adresse invalide et que du tentes de le dérérencer (voir plus) ca provoque un ub
Citation : - INVALID pointe vers une zone mémoire invalide (ya un bug) |
NULL est invalide, apres si tu ne comprends pas qu'il est impossible de déterminer statiquement si une adresse est valide ou pas...
Citation : - free(INVALID): lancer une erreur (signal, throw,...) |
en fait ca n'a aucun interet, si on raisonne systématiquement comme ca, les controles d'erreurs augementeront exponentielement, c'est à l'appelant d'assurer la validité de l'adresse
Citation : Ce que je constate: NULL est utilisé à la fois comme NULL (aucun objet) et INVALID (objet invalide). |
NULL c'est une adresse certifié invalide pour pouvoir etre différencié d'une adresse valide, apres tu en fais ce que tu veux.
Marsh Posté le 10-04-2006 à 19:29:58
Lit le IEEE 754 sur les nombres flottants, compare les QNAN et les SNAN.
http://steve.hollasch.net/cgindex/ [...] float.html
Demande toi si ça serait interessant d'avoir l'équivalent des SNAN et des QNAN avec les pointeurs. Si oui, comment les appellerais-tu?
Sinon laisse tomber.
Marsh Posté le 10-04-2006 à 19:49:32
Citation : Demande toi si ça serait interessant d'avoir l'équivalent des SNAN et des QNAN avec les pointeurs. Si oui, comment les appellerais-tu? |
aucun rapport
moi je comprends pas pourquoi toi tu refuses de comprendre que NULL est une adresse invalide, que ca serait forcement redondant avec ton INVALID, et qu'elle sert juste à gérér des cas "exceptionnels" (comme un bouche-trou)
Marsh Posté le 10-04-2006 à 20:32:17
Je crois que c'est le free(NULL) qui te perturbe.
Faut pas. C'est juste une exception.
Quant au comportement de realloc() sur NULL, c'est tout bête, il est défini que s'il n'y a rien à réallouer, realloc() alloue tout court (== malloc).
Autrement, NULL qualifie bien un pointeur invalide. L'adresse NULL n'existe pas, chaque fois qu'on teste la validité d'un pointeur, c'est avec cette constante que ça se fait, et quand une fonction assume que le pointeur est valide, et qu'il ne l'est pas, ça plante (ou mieux, c'est parfois détecté à la compilation).
NULL == invalide. Dans tous les cas. C'est pas un faux NaN discret, c'est pas du bricolage, c'est sa vraie signification.
Marsh Posté le 09-04-2006 à 16:46:26
Je voudrai savoir s'il y a une différence entre delete p et p = NULL (p etant un pointeur).