Appelant delete sur une variable allouée sur la pile
-
22-07-2019 - |
Question
Ignorer le style et la conception de la programmation est-il "sûr"? 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;
}
La solution
Non , ce n'est pas safe to call delete
sur une variable affectée à une pile. Vous ne devez appeler delete
que sur les éléments créés par new
.
- Pour chaque
malloc
oucalloc
, il devrait y avoir exactement unlibre
. - Pour chaque
nouveau
, il devrait y avoir exactement unsupprimer
. - Pour chaque
nouveau []
, il devrait y avoir exactement unsupprimer []
. - Pour chaque allocation de pile, il ne doit y avoir aucune libération ou suppression explicite. Le destructeur est appelé automatiquement, le cas échéant.
En général, vous ne pouvez pas associer ces éléments, par exemple. pas de free
-ing ou supprimer []
-ing un objet new
. Cela entraîne un comportement indéfini.
Autres conseils
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.
N'oubliez pas que lorsque vous allouez un bloc de mémoire à l'aide de new (ou de malloc, par ailleurs), le bloc de mémoire réellement alloué sera plus volumineux que ce que vous avez demandé. Le bloc de mémoire contiendra également des informations de comptabilité de sorte que lorsque vous libérez le bloc, il peut facilement être remis dans le pool libre et éventuellement être 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 si c'était le cas et les résultats seraient imprévisibles (généralement mauvais).
Oui, il s'agit d'un comportement non défini: transmettre à delete
tout ce qui ne vient pas de new
est UB:
Standard 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 tel est le cas, et si la fonction de désallocation est fournie dans la bibliothèque standard, l'appel de la fonction de désallocation est sans effet. Sinon, la valeur fournie à l'opérateurdelete (void *)
dans la bibliothèque standard doit être l'une des valeurs renvoyées par un précédent appel de l'un des opérateursnew (std :: size_t)
ouopérateur new (std :: size_t, const std :: nothrow_t & amp;)
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, il est généralement "rien ne se passe tout de suite": le désallocation d'un bloc de mémoire non valide peut avoir des conséquences graves sur les prochains appels à l'allocateur.
Après avoir joué un peu avec g ++ 4.4 dans Windows, j'ai obtenu des résultats très intéressants:
-
appeler supprimer sur une variable de pile ne semble rien faire. Aucune erreur ne se produit, mais je peux accéder à la variable sans problème après la suppression.
-
Le fait d'avoir une classe avec une méthode avec
delete this
supprime avec succès l'objet s'il est alloué dans le tas, mais pas s'il est alloué dans la pile (s'il est 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 arriver. Ne faites pas cela.
Non, La mémoire allouée à l'aide de new doit être supprimée à l'aide de l'opérateur delete et que alloué en utilisant malloc devrait être supprimé en utilisant free. Et pas besoin de désallouer les variables qui sont allouées sur la pile.
Un ange perd ses ailes ... Vous ne pouvez appeler delete
que sur un pointeur auquel est attribué new
, sinon vous obtenez un comportement indéfini.
ici, la mémoire est allouée en utilisant la pile, donc inutile de la supprimer de manière externe, mais si vous avez allcoted dynamiquement
aime int * a = new int ()
alors vous devez supprimer a et non supprimer & a (un lui-même est un pointeur), car la mémoire est allouée à partir de la mémoire libre.
Vous avez déjà répondu à la question vous-même. delete
ne doit être utilisé que pour les pointeurs choisis via new
. Faire autre chose est un comportement simple et indéfini.
Par conséquent, rien ne dit vraiment ce qui se passe, que ce soit que le code fonctionne correctement, en passant par le plantage ou l'effacement de votre disque dur est un résultat valable. Alors s'il vous plaît, ne faites jamais cela .
C'est UB parce que vous ne devez pas appeler delete sur un élément qui n'a pas été alloué dynamiquement avec new. C'est aussi simple que cela.