web-dev-qa-db-fra.com

Comment intercepter l'exception de pointeur nul?

  try {
        int* p = 0;
        *p = 1;
    } catch (...) {
        cout << "null pointer." << endl;
    }

J'ai essayé d'attraper l'exception comme ça mais ça ne marche pas, une aide?

39
mindhacks

Il n'y a rien de tel que "exception de pointeur nul" en C++. Les seules exceptions que vous pouvez intercepter sont les exceptions explicitement levées par les expressions throw (plus, comme Pavel l'a noté, certaines exceptions C++ standard levées intrinsèquement par la norme operator new, dynamic_cast etc). Il n'y a aucune autre exception en C++. Le déréférencement de pointeurs nuls, la division par zéro, etc. ne génère pas d'exceptions en C++, il produit comportement indéfini. Si vous souhaitez que des exceptions soient levées dans des cas comme celui-ci, il est de votre responsabilité de détecter manuellement ces conditions et de faire throw explicitement. Voilà comment cela fonctionne en C++.

Tout ce que vous semblez chercher a à voir avec le langage C++, mais plutôt une caractéristique d'implémentation particulière. Dans Visual C++, par exemple, les exceptions système/matériel peuvent être "converties" en exceptions C++, mais il y a un prix attaché à cette fonctionnalité non standard, qui ne vaut normalement pas la peine d'être payé.

56
AnT

Vous ne pouvez pas. Déréférencer un pointeur nul est une chose système.

Sous Linux, le système d'exploitation émet des signaux dans votre application. Jetez un œil à csignal pour voir comment gérer les signaux. Pour en "attraper" une, vous devez accrocher une fonction qui sera appelée dans le cas de SIGSEGV. Ici, vous pouvez essayer d'imprimer certaines informations avant de terminer le programme avec élégance.

Windows utilise gestion des exceptions structurées . Vous pouvez utiliser les informations __try/__except, comme indiqué dans le lien précédent. La façon dont je l'ai fait dans un certain utilitaire de débogage que j'ai écrit était avec la fonction _set_se_translator (car il correspond étroitement aux crochets). Dans Visual Studio, assurez-vous que SEH est activé. Avec cette fonction, vous pouvez connecter une fonction à appeler lorsque le système lève une exception dans votre application; dans votre cas, il l'appellerait avec EXCEPTION_ACCESS_VIOLATION. Vous pouvez ensuite lever une exception et la faire se propager comme si une exception avait été levée en premier lieu.

25
GManNickG

Le déréférencement d'un null (ou d'un pointeur dépassant la fin du tableau ou d'un pointeur non valide aléatoire) entraîne un comportement indéfini. Il n'y a aucun moyen portable de "capturer" cela.

9
Pavel Minaev

Il existe un moyen très simple de détecter tout type d'exception (division par zéro, violation d'accès, etc.) dans Visual Studio en utilisant try -> catch (...) blocs.

Un petit ajustement de projet suffit. Activez simplement le /EHa option dans les paramètres du projet. Voir Propriétés du projet -> C/C++ -> Génération de code -> Modifiez les Activer les exceptions C++ en "Oui avec les exceptions SEH" . C'est ça!

Voir les détails ici: http://msdn.Microsoft.com/en-us/library/1deeycx5 (v = vs.80) .aspx

7
Volodymyr Frytskyy

C++ ne fait pas de vérification de pointeur (bien que je suppose que certaines implémentations le pourraient). Si vous essayez d'écrire sur un pointeur nul, il est fort probable qu'il se bloque brutalement. Il ne lèvera pas d'exception. Si vous voulez attraper cela, vous devez vérifier vous-même la valeur du pointeur avant d'essayer d'y écrire.

5
Nate C-K

En général, vous ne pouvez pas. Même si vous le pouviez, ce serait comme essayer de mettre un pansement sur un sous-marin qui a jailli d'une fuite.

Une application paralysée peut faire beaucoup plus de dégâts qu'une application qui s'est écrasée. Mon conseil ici serait de le laisser planter puis de corriger pourquoi il s'est planté. Rincer. Répéter.

3
0xC0DEFACE

Il n'y a aucun moyen indépendant de faire cela. Sous Windows/MSVC++, vous pouvez utiliser __ try /__ sauf

Mais je ne recommanderais pas de le faire de toute façon. Vous ne pouvez presque certainement pas récupérer correctement d'un défaut de segmentation.

1
Axel Gneiting

Comme d'autres l'ont dit, vous ne pouvez pas faire cela en C++.

Si je peux faire un point plus large: même dans un langage qui vous permet de l'attraper, la meilleure action est de ne pas toucher les pointeurs nuls. Attraper une erreur lorsqu'elle est déjà explosée dans votre visage, puis décider de continuer comme si cela ne s'était pas produit, n'est pas une bonne stratégie de codage. Des choses comme la déréférence de pointeur nul, le débordement de pile, etc., doivent être considérées comme des événements catastrophiques et évitées de manière défensive, même si votre langage vous permet de réagir différemment.

1
asveikau

Si vous le vouliez, vous pouvez simplement vérifier le pointeur et lancer ...

if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();

alors bien sûr ce ne serait que pour déboguer le problème, le nullptr ne devrait pas se produire en premier lieu :)

0
Jan Wilmans

Réponse courte - vous ne pouvez pas le faire de manière portable ou standard, car des bogues comme celui-ci peuvent potentiellement corrompre le processus lui-même.

Réponse longue - vous pouvez faire plus que vous ne le pensez, et certainement plus que la valeur par défaut du programme qui se bloque. Cependant, vous devez garder à l'esprit 3 choses:
1) Ces bogues sont PLUS graves que les exceptions et ne peuvent souvent pas se présenter comme des exceptions à votre logique.
.
3) Il y aura toujours des plantages si graves que vous ne pourrez même pas les détecter avant la fin.

Fondamentalement, les erreurs comme les erreurs de segmentation ou la corruption de tas ne sont pas des exceptions car elles corrompent le processus réel exécutant le programme. Tout ce que vous avez codé dans le programme fait partie du programme, y compris la gestion des exceptions, donc tout ce qui est au-delà de l'enregistrement d'un message d'erreur Nice avant la fin du processus est déconseillé dans les quelques cas, il n'est pas impossible. Dans POSIX, le système d'exploitation utilise un système de signalisation pour signaler des erreurs comme celles-ci, et vous pouvez enregistrer des fonctions de rappel pour consigner l'erreur avant de quitter. Sous Windows, le système d'exploitation peut parfois les convertir en exceptions d'aspect normal que vous pouvez intercepter et récupérer.

En fin de compte, cependant, votre meilleur pari est de coder défensivement contre de tels cauchemars. Sur un système d'exploitation donné, certains seront si mauvais que vous ne pourrez pas les détecter, même en principe, avant la fin de votre processus. Par exemple, corrompre votre propre pointeur de pile est quelque chose qui peut vous planter si mal que même vos rappels de signaux POSIX ne le voient jamais.

0
Zack Yezek

Dans VC++ 2013 (et également dans les versions antérieures), vous pouvez placer des points d'arrêt sur les exceptions:

  1. Appuyez sur Ctrl + Alt + Suppr (cela ouvrira la boîte de dialogue d'exception).
  2. Développez "Exceptions Win32"
  3. Assurez-vous que l'exception "0xC0000005 Violation d'accès" est cochée.

Maintenant, déboguez à nouveau, un point d'arrêt sera atteint exactement lorsque le déréférencement nul s'est produit.