165 votes

Est-ce une bonne pratique de NULL un pointeur après l'avoir supprimé?

Je vais commencer par dire que, l'utilisation des pointeurs intelligents et vous n'aurez jamais à vous inquiéter à ce sujet.

Quels sont les problèmes avec le code suivant?

Foo * p = new Foo;
// (use p)
delete p;
p = NULL;

Cela a été déclenchée par une réponse et commentaires à une autre question. Un commentaire de Neil Butterworth a généré un peu de upvotes:

Réglage des pointeurs à NULL suite de la suppression n'est pas une bonne pratique en C++. Il y a des moments où c'est une bonne chose à faire, et des fois lorsque c'est inutile et peut masquer les erreurs.

Il y a beaucoup de cas où il ne serait pas aider. Mais dans mon expérience, il ne peut pas nuire. Quelqu'un m'éclairer.

101voto

Håvard S Points 11152

Paramètre un pointeur vers 0 (ce qui est "null" dans la norme C++, la valeur NULL est à définir à partir de C est un peu différent) permet d'éviter les accidents sur la double supprime.

Considérez les points suivants:

Foo* foo = 0; // Sets the pointer to 0 (C++ NULL)
delete foo; // Won't do anything

Considérant ce qui suit:

Foo* foo = new Foo();
delete foo; // Deletes the object
delete foo; // Segfault

En d'autres termes, si vous ne définissez pas supprimé les pointeurs à 0, vous allez avoir des ennuis si vous êtes en train de faire double supprime. Un argument contre l'établissement de pointeurs à 0 après la supprimer serait que l'établissement de pointeurs à 0 après la suppression d'eux ne laisse de double supprimer les bugs détectés. C'est à vous, vraiment: Ne vous voulez que votre application de s'écraser sur un double ou pas?

Sur une note concernant la gestion d'allocation des objets, je vous suggère de prendre un coup d'oeil à l' std::unique_ptr strict/singulier de la propriété, std::shared_ptr le partage de la propriété, ou d'un autre pointeur intelligent de mise en œuvre, en fonction de vos besoins.

60voto

jalf Points 142628

Réglage des pointeurs à NULL après que vous avez supprimé ce qu'elle a fait à peut certainement pas de mal, mais c'est souvent un peu de bande-aide sur un problème plus fondamental: Pourquoi êtes-vous à l'aide d'un pointeur en premier lieu? Je vois deux raisons typiques:

  • Que vous vouliez simplement quelque chose alloué sur le tas. Auquel cas, en l'enveloppant dans un RAII objet aurait été beaucoup plus sûr et plus propre. La fin de la RAII de l'objet de la portée lorsque vous n'avez plus besoin de l'objet. C'est combien de std::vector , et il résout le problème de l'accidentellement en laissant des pointeurs vers de désallouer la mémoire autour de. Il n'y a pas de pointeurs.
  • Ou peut-être vous vouliez un peu complexe le partage de la propriété sémantique. Le pointeur retourné à partir de new pourrait ne pas être le même que celui qu' delete est appelé. Plusieurs objets peuvent avoir utilisé l'objet en même temps dans l'intervalle. Dans ce cas, un pointeur partagé ou quelque chose de similaire aurait été préférable.

Ma règle d'or est que si vous laissez des pointeurs partout dans le code de l'utilisateur, vous le faites Mal. Le pointeur ne devrait pas être là à point à ordures en premier lieu. Pourquoi n'est-il pas un objet de prendre la responsabilité de s'assurer de sa validité? Pourquoi ne pas de son champ d'application fin, quand le fait-à l'objet?

45voto

Don Neufeld Points 12803

J'ai une meilleure pratique encore meilleure: dans la mesure du possible, mettez fin à la portée de la variable!

 {
    Foo* pFoo = new Foo;
    // use pFoo
    delete pFoo;
}
 

33voto

Adrian McCarthy Points 17018

J'ai toujours mis un pointeur vers NULL (désormais nullptr) après la suppression.

  1. Il peut aider à capturer de nombreuses références à la libre avais de la mémoire (en supposant que votre plate-forme de défauts sur un deref d'un pointeur null).

  2. Il ne prends pas toutes les références à la libre avais de la mémoire, par exemple, si vous avez une copie du pointeur de la souris qui traînent. Mais certains sont mieux que rien.

  3. Il masque une double-supprimer, mais je trouve ceux-ci sont beaucoup moins fréquents que les accès déjà libéré de la mémoire.

  4. Dans de nombreux cas, le compilateur va optimiser loin. Donc, l'argument qu'il est inutile de ne pas me persuader.

  5. Si vous utilisez déjà RAII, il n'y a pas beaucoup de deletes dans votre code, pour commencer, de sorte que l'argument le fait que le supplément d'attribution de causes de l'encombrement de ne pas me persuader.

  6. Il est souvent pratique, lors du débogage, pour voir la valeur null plutôt que d'un état de pointeur.

  7. Si cela dérange encore, vous pouvez utiliser un smart pointeur ou une référence à la place.

J'ai également définir d'autres types de ressources des poignées pour le non-valeur des ressources lorsque la ressource est libre (qui est en général seulement dans le destructeur d'une RAII wrapper écrit encapsuler les ressources).

J'ai travaillé sur un grand (9 millions de dollars des états) produit commercial (principalement en C). À un moment donné, nous avons utilisé la macro de la magie à NULL le pointeur lorsque la mémoire a été libérée. Immédiatement exposée plein de tapie bugs qui ont été rapidement résolus. Aussi loin que je me souvienne, nous n'avons jamais eu un double sans bug.

Mise à jour: Microsoft estime que c'est une bonne pratique pour la sécurité et recommande la pratique dans leur SDL politiques. Apparemment MSVC++11 stomp supprimés pointeur automatiquement (dans de nombreux cas) si vous compilez avec l' /SDL option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X