web-dev-qa-db-fra.com

Comment détecter si un pointeur a été supprimé et le supprimer en toute sécurité?

Dans C++ Comment décider ou savoir si un pointeur a été supprimé auparavant ??

lorsque j'ai essayé de supprimer un pointeur précédemment supprimé dans une autre partie du code, il a levé une exception qui ne peut pas être gérée.

Je me demandais s'il y avait un moyen de vérifier ou d'essayer de supprimer le pointeur? toute référence sur les opérations de mémoire avancées.

aussi je veux maîtriser les exceptions non gérées des pointeurs et l'accès à protégé ou l'accès est une violation, ... ce genre d'erreur.

merci pour ceux qui donnent une partie de leurs connaissances et de leur temps pour aider les autres et partager leurs bénéfices


Mettre à jour

Le gros conseil de la communauté des développeurs c ++ modernes est le suivant: Utilisez des pointeurs intelligents ou évitez d’utiliser des pointeurs bruts. Mais pour des raisons de sécurité et d’assurance que vous n’avez pas de mémoire ( ISO_CPP_FAQ ) et, bien sûr, si vous voulez éviter le peu de temps système nécessaire pour utiliser des pointeurs intelligents avec des pointeurs bruts [type *] - ce n'est pas général. Préférer toujours les pointeurs intelligents aux pointeurs bruts.

Dans «Going Native 2013», un conseil commun était le suivant: n'utilisez jamais d'indicateurs bruts.

20
ahmedsafan86

Il peut y avoir trois solutions. Vous voudrez peut-être en choisir un en fonction du rapport effort/qualité que vous souhaitez atteindre: 

Solution élégante et la plus correcte: 

Utilisez pointeurs intelligents et vous n’aurez plus jamais à appeler manuellement delete. C'est le meilleur moyen possible de surmonter ce problème. Il utilise le principe de RAII qui fonctionne parfaitement pour un langage comme C++ qui n’a pas de récupérateur de déchets intégré. 

Solution moins élégante mais pratique: 

Attribuez le pointeur à NULL après la suppression. L'appel de delete sur un pointeur NULL est une opération irréprochable. Il n'est donc plus nécessaire d'avoir cette vérification NULL supplémentaire, mais cela pourrait masquer certains problèmes au lieu de les rendre visibles. 

Solution moins élégante mais plus correcte: 

Traquez tous les multiples problèmes delete en laissant votre programme planter. Vous pouvez également utiliser des programmes d’analyseur de mémoire tels que valgrind, puis corriger votre code pour éviter tous ces problèmes.

25
Alok Save

C'est une bonne question, mais l'une des vérités fondamentales du travail dans un environnement géré manuellement par la mémoire (comme C/C++ et ses cousins) est qu'il n'y a pas de bonne façon de regarder un pointeur après le fait c'est valide - une fois que c'est devenu invalide, il est parti, et le regarder est sujet à exploser. Votre travail consiste à vous assurer qu'il n'est jamais supprimé ou libéré plus d'une fois et qu'il n'est jamais consulté après cette heure.

Regardez certainement les pointeurs intelligents, qui ont été inventés pour rendre la vie du programmeur plus facile dans ces circonstances. (La méthode plus traditionnelle consiste à faire attention à ne pas tout gâcher, puis à affecter NULL au pointeur lorsque vous savez qu'il a été supprimé, comme le dit Alok.)

4
Ben Zotto

En C++ Comment décider ou savoir si un pointeur a été supprimé auparavant ??

La norme linguistique n'offre aucun moyen légal de déterminer si un pointeur arbitraire est valide ou non.

Il y a un moyen, mais il dépend fortement du compilateur/du système d'exploitation. Vous pouvez soit vous connecter au gestionnaire de mémoire existant, soit le remplacer par le vôtre et fournir une fonction dédiée à la validation du pointeur. Ce n'est peut-être pas très facile à faire, cependant. Et vous ne voulez pas vraiment vous fier à cette fonctionnalité si les performances sont essentielles.

3
Alexey Frunze

Le pointeur ne vous dira rien. Votre conception doit: si Vous utilisez une allocation dynamique, c’est normalement car votre application Requiert que l’objet ait une durée de vie spécifique, doncvous savez quand l’objet sera correctement supprimé. Si l'objet est copiable, ou a une durée de vie qui correspond à la portée, vous ne l'allouez pas (normalement) dynamiquement. 

Il existe bien sûr des exceptions dans le code de très bas niveau - si Vous implémentez quelque chose comme std::vector, vous devrezutiliser une sorte d’allocation dynamique, car la taille n’est pas Connue à temps de compilation. Mais de telles allocations ne doivent pas échapper. C'est la responsabilité de la classe de bas niveau de gérer la mémoire

Enfin, les dépassements de mémoire tampon, l’accès à la mémoire déjà supprimée et le comportement similaire sont des comportements indéfinis. En général, ils ne génèrent pas d’exception et il n’existe pas de méthode générique pour les gérer. (Vous pouvez généralement vous arranger pour obtenir un signal lorsque De telles choses se produisent, mais il y a si peu de choses que vous pouvez faire avec un gestionnaire de signaux , Cela n'aide pas beaucoup.) En général, ce que vous voulez, c’est que le programme plante, car vous ne savez pas dans quel état il se trouve. Dans les rares cas où ce n’est pas lecase, vous devez vous replier sur la mise en oeuvre définie extensions, si elles existent. Si vous compilez avec l'option /EHa Avec VC++, par exemple, ce qui serait normalement un blocage Sera converti en une exception C++. Mais c’est une extension VC++ Et vous ne connaissez toujours pas l’état général du programme Lorsque cela se produit. Si c'est parce que vous avez corrompu l'arène d'espace libre, vous ne pouvez probablement rien faire, même sivous attrapez l'exception (et il y a de fortes chances que vous obteniez Une autre exception d'un destructeur essayant pour libérer de la mémoire lorsque vous déroulez la pile).

2
James Kanze

utilisez shared_ptr<> et shared_array<>, n'oubliez pas que shared_ptr<> peut être utilisé pour gérer la mémoire allouée à un tableau uniquement si Deleter est fourni, sinon utilisez shared_array<> pour gérer vos tableaux.

A* a_tab=new A[100];
boost::shared_ptr<A> a_tab_ok(a_tab,ArrayDeleter<A>()); 

// ok seulement si

template <typename T>
    class ArrayDeleter
    {
    public:
        void operator () (T* d) const
        {
            delete [] d; //will delete array!
        }
    };

est fourni

2
4pie0

Je sais que ce fil est vieux. Mais si quelqu'un d'autre lit ceci, il devrait connaître unique_ptr. shared_ptr a en effet une surcharge. Le compteur est stocké sur le tas. À chaque accès au compteur, il existe un risque de non concordance dans le cache du processeur. unique_ptr Est plus limité mais ne génère pas de surcharge par rapport aux pointeurs ordinaires. Ma suggestion est de préférer unique_ptr à shared_ptr lorsque vous n’avez pas besoin de compter les références . Un autre avis important est que unique_ptr fonctionne bien avec les tableaux . Si je me souviens bien, c’est également vrai pour shared_ptr depuis C++ 17.

1
Martin Fehrs

Les pointeurs intelligents sont un meilleur choix pour éviter de tels problèmes (mais vous devez avoir une compréhension complète avant de les utiliser également), mais je voudrais mentionner les limitations de performances associées aux pointeurs intelligents, car ils utilisent généralement des opérations atomiques, par exemple InterlockedIncrement dans l'API Win32 pour référence compte. Ces fonctions sont nettement plus lentes que l'arithmétique des nombres entiers simples. Je ne suis pas sûr qu'une telle pénalité de performance soit acceptable ou non dans votre cas.

Ce que je fais habituellement est (donc je n'ai pas à passer des jours plus tard à déboguer des bugs méchants), je passe beaucoup de temps à la conception et à la durée de vie des objets, avant de passer à un codage réel, car je supprime la mémoire, je définis spécifiquement le pointeur NULL, c'est une bonne pratique pour autant que je le pense. Encore une fois, la vraie solution est peut-être de passer plus de temps à déterminer les dépendances et la durée de vie des objets avant de continuer! 

1
Saqlain