C++ : TP 5 - Exceptions

© D. Mathieu     mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique
Créé le 16/01/2000 - Dernière mise à jour : 25/01/2001

Remarques préliminaires :

Sommaire

Exception entière
Traitant local  exo_01a
Propagation à la fonction main()  exo_01b
 exo_01
Sortie de boucle par une exception  exo_02
Capture d'exception avec/sans conversion ?  exo_03
Mode de passage de l'exception au bloc catch
Donnée passée par référence  exo_04a
Donnée passée par copie  exo_04b
Donnée passée par copie  exo_04c
Donnée-résultat  exo_04d
 exo_04
Exceptions standard  exo_05
Exceptions utilisateur  exo_06


Exception entière

exo_01

    Contrairement à Ada, tout objet, toute valeur peut servir d'exception en C++. La valeur de l'objet est la valeur de l'exception, qui n'est donc pas d'un type spécifique.


exo_01a

    Dans la fonction Exo_01() de l'espace de noms anonyme du fichier exo_01a.cxx, initialiser une variable (ou une constante) entière non nulle Num, et lire au clavier le dénominateur Denom, lui aussi entier. Tester le dénominateur (schéma alternatif) :

    Pour écrire ce schéma alternatif, consulter le document "Normes de programmation C++ internes : Rupture de séquence".

    Sécuriser l'ensemble du corps de la fonction Exo_01a() en l'incluant dans une instruction try-catch. Dans le traitant de l'exception capturée, afficher  la valeur de l'exception dans le flux d'erreur.

    Compiler et tester.

Corrigés : exo_01a.cxx

Sommaire


exo_01b

    Recopier le fichier exo_01a.cxx dans exo_01b.cxx. Dans la fonction Exo_01(), modifier le traitant d'exception pour qu'il relève l'exception après l'affichage.

    Modifier le corps de la fonction main() pour permettre la capture de toute exception, quelle qu'elle soit. Dans le traitant correspondant, l'exception ne pouvant être identifiée, afficher le message :
 
Exception inconnue reçue dans la fonction main()

et renvoyer la constante entière (short) CstExcInconnue (= 255).

    Compiler et tester. Vérifier que le c-shell a bien reçu la valeur renvoyée par la fonction main() :
 
duo>echo $status

Corrigés : exo_01b.cxx

Sommaire


Sortie de boucle par une exception

exo_02

    Le contrôle des instructions d'un programme peut être modifié de façon brutale par une exception levée à un endroit et capturée ailleurs. Bien que peu recommandée en général, cette méthode est parfois indispensable.

    Recopier le fichier exo_01b.cxx dans exo_02.cxx. Dans la fonction Exo_02(), initialiser une constante entière non nulle Num, et, dans une boucle infinie, lire au clavier le dénominateur Denom, lui aussi entier. Ne sortir de la boucle, en levant une exception entière, comme ci-dessus, que si Denom est positif. Il faudra bien entendu utiliser un bloc try-catch, même si le traitant d'exception est vide. Afficher le résultat de la division entière avant de retourner de la fonction Exo_02().

    Compiler et tester.

Remarques :

  1. Cet exercice n'est effectué qu'à titre de démonstration. Dans la pratique, il est préférable d'utiliser simplement une instruction :
     
    if (Denom > 0) break;
  2. A titre de curiosité, après avoir saisi un nombre négatif, taper un caractère invalide au lieu de l'entier demandé. Vous constatez que le programme tourne indéfiniment. Cela est dû au fait que l'extraction ayant échoué, la valeur de Denom n'est pas modifiée et le caractère invalide n'est pas extrait.

Corrigés : exo_02.cxx

Sommaire


Capture d'exception avec/sans conversion ?

exo_03

    Contrairement à Ada, le langage C++ effectue de nombreuses conversions implicites lorsque des paramètres formels et effectifs sont de types compatibles. Il est rare par exemple qu'un paramètre effectif d'un type entier quelconque ne puisse être utilisé pour instancier un paramètre formel, lui-même d'un type entier quelconque. Cette règle vaut-elle pour une exception ?

    Dans la fonction Exo_03(), lever une exception de type unsigned int dans un bloc try-catch. Ecrire un traitant d'exception de type unsigned int qui affiche l'exception reçue.

    Tester.

    Après le traitant ci-dessus, ajouter un traitant d'exception de type int qui affiche l'exception reçue.

    Tester. Quel est le traitant qui est exécuté ?

    Intervertir les deux traitants d'exceptions.

    Tester. Quel est le traitant qui est exécuté ?

    Mettre en commentaire le traitant d'exception de type unsigned int.

    Tester. L'exception levée (qui est de type unsigned int) est-elle convertie en entier int ?

Corrigés : exo_03.cxx

Sommaire


Mode de passage de l'exception au bloc catch

exo_04

    La syntaxe du traitant d'exception catch() est très semblable à celle d'une signature (un profil) de fonction avec un seul paramètre formel, du type de l'exception que l'on désire traiter. Comme tout paramètre formel, l'exception peut être passée par valeur ou par référence, constante ou pas.


exo_04a

    Recopier le fichier exo_03.cxx dans exo_04a.cxx. Dans la fonction Exo_04(), construire un bloc try-catch dont le traitant (bloc catch) capture un string (paramètre donnée passé par référence) et l'affiche. Dans le corps de l'instruction try-catch (bloc try), imbriquer un autre bloc try-catch dont le traitant capture (paramètre donnée passé par référence) un string, l'affiche, la modifie et la relève par throw.

    Compiler. Vous ne devriez aller guère plus loin ...

Corrigés : exo_04a.cxx

Sommaire


exo_04b

    Recopier le fichier exo_04a.cxx dans exo_04b.cxx. Dans le bloc try-catch  interne, remplacer le paramètre donnée passé par référence par un paramètre passé par valeur.

    Compiler et tester. Vous devez constater que la modification interne de l'exception n'a pas affecté l'exception qui est en cours de traitement et qui est relevée telle qu'elle a été interceptée.

Corrigés : exo_04b.cxx

Sommaire


exo_04c

    Recopier le fichier exo_04b.cxx dans exo_04c.cxx. Dans le bloc try-catch interne, remplacer l'instruction throw; par throw ident; ident est l'identificateur du paramètre.

    Compiler et tester. Vous constatez que l'exception relevée n'est pas celle qui a été capturée, mais sa copie locale et modifiée.

Corrigés : exo_04c.cxx

Sommaire


exo_04d

    Recopier le fichier exo_04b.cxx dans exo_04d.cxx. Dans le bloc try-catch interne, remplacer le paramètre donnée passé par valeur par un paramètre donnée-résultat (donc passé par référence).

    Compiler et tester. Vous constatez que l'exception relevée, qui est celle qui a été capturée, a été modifiée au sein du traitant d'exception interne.

Corrigés : exo_04d.cxx

Sommaire


Exceptions standard

exo_05

    La norme C++ a prévu un certain nombre d'exceptions standard correspondant à plusieurs circonstantes différentes. Malheureusement, la plupart ne sont pas implémentées dans la version du compilateur que nous utilisons actuellement. Nous pouvons cependant en mettre quelques-unes en évidence.

    Dans la fonction Exo_05(), construire et initialiser une chaîne string. Dans un bloc try-catch, essayer d'insérer un caractère dans une position invalide. En principe, l'exception out_of_range devrait être attendue. Par prudence, ajouter aussi un traitant d'exception pour les exceptions de la classe standard exception. Compiler et tester.

    Ajouter un second bloc try-catch. Essayer d'accéder à un élément d'indice invalide par l'opérateur []. L'exception out_of_range est-elle levée ?

    Remplacer l'opérateur [] par la fonction at(). L'exception out_of_range est-elle levée ?

Corrigés : exo_05.cxx

Sommaire


Exceptions utilisateur

exo_06

    Dans la fonction Exo_06(), construire un bloc try-catch, lever une exception standard de la classe exception, la capturer et afficher son contenu au moyen de la fonction what().

    Compiler et tester.

    Ajouter à l'espace de noms anonyme (avant la fonction Exo_06()) la classe CExc par dérivation publique de exception. Faire précéder la levée de l'exception exception par la levée d'une exception CExc. Capturer cette exception et afficher son contenu (toujours par la fonction héritée what()).

    Compiler et tester.

Corrigés : exo_06.cxx

Sommaire


Téléchargement des corrigés :

tpexcept.zip

Chemins d'accès aux sources des corrigés :

~mathieu/PARTAGE/src/tp/tpC++/tpexcept/direxcept

© D. Mathieu     mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique