Pourquoi devrais-je essayer de ne pas utiliser « cette » valeur après « supprimer ce »?
-
18-09-2019 - |
Question
Restrictions 1 à 3 semblent tout à fait raisonnable. Mais pourquoi est-il restriction 4 que je « ne doit pas l'examiner, le comparer avec un autre pointeur, comparer avec NULL, l'imprimer, le lancer, quelque chose avec elle »?
Je veux dire this
est encore un autre pointeur. Pourquoi ne puis-je reinterpret_cast
à un int
ou un appel printf()
à la sortie de sa valeur?
La solution
La raison pour laquelle vous ne pouvez pas faire quoi que ce soit avec un pointeur après avoir supprimé (ceci, ou tout autre pointeur), est que le matériel pourrait (et quelques machines faisaient les anciens) piège essayant de charger une adresse mémoire invalide dans un registre. Même si elle peut être très bien sur tout le matériel moderne, la norme dit que la seule chose que vous pouvez faire à un pointeur non valide (non initialisée ou supprimé), est de lui assigner (soit NULL, soit d'un autre pointeur valide).
Autres conseils
La valeur de « ceci » après avoir appelé la suppression est définie et le comportement de tout ce que vous faites avec elle est également définie. Alors que je me attends à la plupart des compilateurs de faire quelque chose sensible, il n'y a rien (dans la spécification) arrêter le compilateur de décider que son comportement dans ce cas particulier sera émette code pour formater votre disque dur. Comportement non défini est l'invocation (presque) toujours une erreur, même si votre compilateur particulier se comporte de la façon dont vous souhaitez qu'il.
Vous pouvez contourner ce problème en prenant une copie du pointeur (comme un entier) avant d'appeler supprimer.
Aha!
3.7.3.2/4. » ... la fonction désallocation doit désaffecter le stockage référencé par le pointeur, ce qui rend invalide tous les pointeurs se rapportant à une partie du stockage désallouées L'effet d'utiliser une valeur de pointeur non valide (y compris le transmettre une fonction de désallocation) est indéfini ».
Notez que cela dit « en utilisant la valeur », et non « déréférencement le pointeur ».
Ce paragraphe est pas spécifique à this
, il applique à tout ce qui a été supprimé.
parce que toute action que vous pouvez prendre avec ce pointeur pourrait déclencher une logique qui est interprétée sur les méthodes de la classe de cet objet, ce qui pourrait conduire à un accident.
Maintenant, quelques-unes des actions que vous pointez à pourrait être apparemment « sûr », mais il est difficile de dire ce qui se passe dans une méthode que vous pouvez appeler.
De la poste: « ne doit pas l'examiner, le comparer avec un autre pointeur, comparer avec NULL, l'imprimer, le lancer, quelque chose avec elle »
Toutes ces actions peuvent déclencher des fonctions liées à l'opérateur, qui sont évalués avec un pointeur non défini. Idem pour la coulée.
Maintenant, si vous effectuez une reintepret_cast, qui est probablement une autre histoire, et vous pourriez probablement obtenir avec elle, comme réinterpréter est juste un peu par réinterprétation de bits, sans faire intervenir (pour autant que je sache) un appel de méthode.
Pour la même raison que vous ne supprimez tout autre pointeur et puis essayer d'effectuer toute opération sur elle.
b / c l'adresse que cela se réfère maintenant, il non défini, et vous ne savez pas ce qui pourrait être là ...
Dans un programme multi-thread, le moment où vous delete
un pointeur, l'espace libre peut être attribuée par un autre thread, en écrasant l'espace utilisé par this
. Même dans un seul programme-fil, à moins que vous êtes très attention à ce que vous appelez avant return
ing, tout ce que vous faites après delete this
pourrait allouer de la mémoire et de remplacer ce qui était pointée par this
.
Dans un Microsoft Visual C ++ exécutable compilé en mode débogage, delete
ing un pointeur provoque sa mémoire pour être immédiatement remplacées par un modèle de test 0xCC (variables non initialisées sont également initialisés avec ce modèle), pour aider à identifier les bugs pointeur ballants comme celui une.
Cela me rappelle quand je fixe un bug dans un jeu en ligne jouable dans lequel un constructeur de l'objet Feu supprimé le plus ancien feu si le nombre total d'incendies a atteint un certain nombre. Le feu supprimé était parfois le feu parent créant un nouveau feu - bam, ballants bug pointeur! Il est seulement dû à la chance que ce bug a interagi avec l'algorithme d'allocation de mémoire d'une manière complètement prévisible (le feu a toujours été écrasé par un nouveau feu de la même manière supprimé) - sinon, il y aurait eu une désynchronisation entre les joueurs en ligne. J'ai trouvé ce bogue lors de la réécriture de la façon dont le jeu a fait l'allocation de mémoire. En raison de sa prévisibilité, quand je l'ai fixé, je suis également en mesure de mettre en œuvre l'émulation de son comportement pour la compatibilité avec les clients de jeu plus.