web-dev-qa-db-fra.com

Appel de suppression sur une variable allouée sur la pile

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;
}
54
unistudent

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.

  • Pour chaque malloc ou calloc, il devrait y avoir exactement un free.
  • Pour chaque new, il devrait y avoir exactement un delete.
  • Pour chaque new[] il devrait y en avoir exactement un delete[].
  • Pour chaque allocation de pile, il ne doit pas y avoir de libération ou de suppression explicite. Le destructeur est appelé automatiquement, le cas échéant.

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.

98
Mr Fooz

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.

46
Jeremy Ruten

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).

14
Ferruccio

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 de operator new(std::size_t) ou operator 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.

10
dasblinkenlight

Après avoir joué un peu avec g ++ 4.4 dans Windows, j'ai obtenu des résultats très intéressants:

  1. 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.

  2. 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).

7
Sambatyon

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.

5
user529758

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.

4
Vinay

Un ange perd ses ailes ... Vous pouvez uniquement appeler delete sur un pointeur alloué avec new, sinon vous obtenez un comportement indéfini.

3
Luchian Grigore

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.

1
Ashrith

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.

0
Grizzly

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.

0
Martin James