Supprimer le destructeur appelant sans supprimer l’object?

Donc, je travaille avec c ++ et des pointeurs depuis un an et demi maintenant, et je pensais que je les avais réussi. J’ai déjà appelé supprimer des objects plusieurs fois auparavant et les objects ont effectivement été supprimés, ou du moins je pensais qu’ils l’avaient fait.

Le code ci-dessous confond juste l’enfer de moi:

#include  class MyClass { public: int a; MyClass() : a(10) { std::cout << "constructor ran\n"; } void method(std::string input_) { std::cout << param_ << "\n"; } ~MyClass() { std::cout <method("1"); delete ptr; ptr->method("2.5"); } 

ce code affiche:

 constructor ran 1 destructor ran 2.5 

J’étais confus quant à la raison pour laquelle il ne jetait aucune erreur – je m’attendais à une mémoire hors limites ou similaire, mais rien. La boucle for trouvait là, au cas où il y aurait eu une sorte de récupération de place masquée, même si, autant que je sache, il n’existe pas de récupération de place en c ++.

Quelqu’un peut-il expliquer pourquoi ce code fonctionne, ou si je me trompe avec ce code pour qu’il ne me donne pas l’erreur?

Vous comprenez mal ce que delete . Tout delete ne fait qu’appeler le destructeur et informer l’allocateur que cette mémoire est libre. Cela ne change pas le pointeur réel. Tout ce qui est au-delà est non défini.

Dans ce cas, cela ne fait rien aux données réelles pointées. Ce pointeur pointe sur les mêmes données qu’il a précédemment pointées, et l’appel de méthodes dessus fonctionne parfaitement. Cependant, ce comportement n’est pas garanti; en fait, c’est explicitement non spécifié. delete pourrait mettre à zéro les données; ou l’allocateur pourrait allouer la même mémoire pour autre chose, ou le compilateur pourrait simplement refuser de le comstackr.

C ++ vous permet de faire beaucoup de choses dangereuses, dans l’intérêt de la performance. C’est l’un d’eux. Si vous voulez éviter ce genre d’erreur, c’est une bonne idée de faire:

 delete ptr; ptr = NULL; 

pour vous assurer que vous n’essayez pas de réutiliser le pointeur, et se plantera immédiatement si vous le faites plutôt que d’avoir un comportement indéfini.

L’appel de ptr->method("2.5") après la delete ptr a un comportement indéfini . Cela signifie que tout peut arriver, y compris ce que vous observez.

Dans ce code:

 MyClass* ptr = new MyClass; ptr->method("1"); delete ptr; ptr->method("2.5"); 

vous accédez à la mémoire déjà libérée, ce qui donne un comportement indéfini , ce qui signifie que tout peut arriver, même dans le pire des cas: cela semble fonctionner correctement.

C’est l’une des raisons pour lesquelles il est recommandé de définir un tel pointeur sur NULL plutôt que de laisser ce type de choses se produire:

 delete ptr; ptr = NULL; 

Bien que la meilleure chose à faire est d’éviter complètement d’utiliser des pointeurs si possible.

vous accédez à la mémoire, qui n’est pas réinitialisée tant qu’elle n’est pas utilisée par un autre nouvel appel ou presque. Cependant, il est recommandé de définir le pointeur sur NULL chaque fois que vous appelez delete.