Ignorant le style et la conception de la programmation, est-il "sûr" d'appeler delete sur une variable allouée sur la pile?
Par exemple:
int nAmount;
delete &nAmount;
ou
class sample
{
public:
sample();
~sample() { delete &nAmount;}
int nAmount;
}
Non , il n'est pas sûr d'appeler delete
sur une variable allouée à la pile. Vous ne devez appeler delete
que sur les choses créées par new
.
malloc
ou calloc
, il devrait y avoir exactement un free
.new
, il devrait y avoir exactement un delete
.new[]
il devrait y en avoir exactement un delete[]
.En général, vous ne pouvez pas mélanger et assortir ces éléments, par exemple non free
- ing ou delete[]
- un objet new
. Cela entraîne un comportement indéfini.
Eh bien, essayons:
jeremy@jeremy-desktop:~$ echo 'main() { int a; delete &a; }' > test.cpp
jeremy@jeremy-desktop:~$ g++ -o test test.cpp
jeremy@jeremy-desktop:~$ ./test
Segmentation fault
Donc, apparemment, ce n'est pas sûr du tout.
Gardez à l'esprit que lorsque vous allouez un bloc de mémoire en utilisant new (ou malloc d'ailleurs), le bloc de mémoire alloué sera plus grand que ce que vous avez demandé. Le bloc de mémoire contiendra également des informations de comptabilité afin que lorsque vous libérez le bloc, il puisse facilement être remis dans le pool libre et éventuellement fusionné avec des blocs libres adjacents.
Lorsque vous essayez de libérer de la mémoire que vous n'avez pas reçue de nouveau, ces informations de comptabilité ne seront pas là mais le système agira comme tel et les résultats seront imprévisibles (généralement mauvais).
Oui, c'est un comportement indéfini: passer à delete
tout ce qui ne vient pas de new
est UB:
Norme C++, section 3.7.3.2.3: La valeur du premier argument fourni à l'une des fonctions de désallocation fournies dans la bibliothèque standard peut être une valeur de pointeur
null
; si c'est le cas, et si la fonction de désallocation est fournie dans la bibliothèque standard, l'appel à la fonction de désallocation n'a aucun effet. Sinon, la valeur fournie àoperator delete(void*)
dans la bibliothèque standard doit être l'une des valeurs renvoyées par une précédente invocation deoperator new(std::size_t)
ouoperator new(std::size_t, const std::nothrow_t&)
dans la bibliothèque standard.
Les conséquences d'un comportement indéfini sont, bien, indéfinies. "Rien ne se passe" est une conséquence aussi valable que toute autre chose. Cependant, c'est généralement "rien ne se passe tout de suite": la désallocation d'un bloc de mémoire invalide peut avoir de graves conséquences lors d'appels ultérieurs à l'allocateur.
Après avoir joué un peu avec g ++ 4.4 dans Windows, j'ai obtenu des résultats très intéressants:
l'appel de suppression sur une variable de pile ne semble rien faire. Pas d'erreurs, mais je peux accéder à la variable sans problème après la suppression.
Avoir une classe avec une méthode avec delete this
supprime correctement l'objet s'il est alloué dans le tas, mais pas s'il est alloué dans la pile (s'il se trouve dans la pile, rien ne se passe).
Personne ne peut savoir ce qui se passe. Cela appelle un comportement indéfini, donc tout peut littéralement se produire. Ne faites pas ça.
Non, la mémoire allouée à l'aide de new doit être supprimée à l'aide de l'opérateur delete et celle allouée à l'aide de malloc doit être supprimée à l'aide de free. Et pas besoin de désallouer la variable allouée sur la pile.
Un ange perd ses ailes ... Vous pouvez uniquement appeler delete
sur un pointeur alloué avec new
, sinon vous obtenez un comportement indéfini.
ici la mémoire est allouée en utilisant la pile donc pas besoin de la supprimer extérieurement mais si vous avez alloué dynamiquement
comme int * a = new int ()
alors vous devez supprimer un et non supprimer & a (un lui-même est un pointeur), car la mémoire est allouée à partir du magasin gratuit.
Vous avez déjà répondu vous-même à la question. delete
ne doit être utilisé que pour les pointeurs achetés via new
. Faire autre chose est un comportement indéfini clair et simple.
Par conséquent, il n'y a vraiment rien à dire sur ce qui se passe, quoi que ce soit, du code fonctionnant correctement au plantage en passant par l'effacement de votre disque dur, est un résultat valide de cette opération. Alors s'il vous plaît ne faites jamais ça.
C'est UB car vous ne devez pas appeler delete sur un élément qui n'a pas été alloué dynamiquement avec new. C'est si simple.