programme de baccalauréat en informatique programmation orientée objets ift-19946 thierry eude...
TRANSCRIPT
Programme de baccalauréat en informatique Programmation Orientée Objets
IFT-19946
Thierry EUDEThierry EUDE
Module 6. Gestion des erreurs et des exceptions :
Fonctionnement et utilisation
Département d’informatique et de génie logiciel
Département d’informatique et de génie logiciel
2
Erreurs et exceptions
On rencontre fréquemment des erreurs ou des exceptions dans les programmes.
Erreurs :•des erreurs d'entrée de données par l'usager•des erreurs du matériel ou de périphérique•des erreurs de limitations ressources du système•des erreurs de programmation de composants logiciels.
Département d’informatique et de génie logiciel
3
Exceptions :
débordement de capacité d'un nombre ;division par zéro ;paramètre de fonction invalide ;connexion réseau non disponible ou interrompue.
Département d’informatique et de génie logiciel
4
• Erreur d'entrée de données de l'utilisateur
L'utilisateur peut :• saisir une date invalide• demander de lire un fichier inexistant• demander d'afficher le contenu de ie dossier qui est en dehors
des limites d'un conteneur.Dans un programme interactif :
- on informe l'utilisateur du problème- on attend de nouvelles directives.
Dans un programme non interactif :- on fait le rapport de l'erreur dans un fichier- on tente de continuer ou on arrête.
Erreurs
Département d’informatique et de génie logiciel
5
• Erreur du matériel ou de périphérique
Exemples :- le port série n'est pas disponible- l'imprimante peut être hors tension ou ne plus avoir de papier.
Arrêt ou suspension de la tâche en attendant que le problème soit réglé.
L'imprimante n'a plus de papier au milieu de la tâche. Le programme peut alors :
• avertir l'utilisateur de la situation• attendre qu'il nous dise quoi faire sans quitter.
Département d’informatique et de génie logiciel
6
• Erreur de limitation de ressources du système
Cas typiques :• disque dur ou disquette plein• plus de mémoire disponible• plus de ressource Windows disponible (Font, Brush...)
Si un scénario est détecté, on peut :• avertir l'utilisateur de la situation en lui demandant de libérer
des ressources (si possible)• attendre ses instructions (réessayer ou annuler) sans quitter le
programme.
Département d’informatique et de génie logiciel
7
• Erreur de programmation d'un composant logiciel
Exemples typiques :• tenter de créer une date invalide• tenter d'obtenir le dessus d'une pile vide• tenter d'obtenir un élément dans un vecteur qui est hors
limite.
difficile d'adopter une stratégie adaptée à toutes les situations :
• parfois, lancer une exception de contrat et arrêter le programme suffit.
• parfois, avertir l'usager, sauvegarder son travail et quitter élégamment est préférable.
Département d’informatique et de génie logiciel
8Réagir à ces conditions d'erreur au niveau du code
•retourner un code d'erreur•assigner une valeur à une variable globale d'erreur•ignorer l'erreur (!)•imprimer un message d'erreur•arrêter le programme•lancer une exception.
Département d’informatique et de génie logiciel
9
• Retourner un code d'erreur
Façon de faire très fréquemment rencontrée dans les programmes :
• une valeur ou un ensemble de valeurs indiquent une situation d'erreur.
Exemple : • la fonction fopen de la librairie du C standard
retourne un pointeur valide si l'ouverture du fichier a été réussie
un pointeur NULL autrement.
FILE* fopen(const char* fichierP);
Département d’informatique et de génie logiciel
10
Le programmeur a la responsabilité de vérifier le code de retour de la fonction pour s'assurer du succès de l'appel :FILE* fP = fopen("toto.txt");if (fP != NULL){ // --- Écrire dans le fichier}else{
// --- Gérer l'erreur}
Département d’informatique et de génie logiciel
11
Dans certains cas, il est difficile de trouver une valeur désignant la situation d'erreur :
• Une fonction qui retourne un entier dont toutes les valeurs peuvent être valides n'a pas vraiment de moyen pour retourner une erreur (0 pouvant être valide).
• Souvent, on rencontre des standards dans lequel toutes les fonctions retournent un code d'erreur. Les valeurs de retour (données en retour) sont passées en paramètre.
Département d’informatique et de génie logiciel
12
Exemple
bool fonct1(double v, int& ret);
int fonct2(double v, int& ret);
fonct1 retourne true en cas de succès et false autrement.fonct2 pourrait retourner différentes valeurs entières
spécifiant des cas d'erreur et un cas valide.
Dans les deux cas, les valeurs retournées passent par les paramètres et le retour ne sert qu'aux codes d'erreur.
Département d’informatique et de génie logiciel
13
• Variable globale d'erreur
La plupart des fonctions de la librairie standard du C fonctionnent avec la célèbre variable globale errno.
Exemple :• si on appelle unlink pour effacer un fichier, la fonction retourne 0 en cas de succès et -1 autrement.
• En cas d'erreur, on a assigné un code d'erreur à la variable globale errno :EACCES: Accès interditENOENT: Chemin d'accès ou fichier introuvable
Département d’informatique et de génie logiciel
14
Exemple
void main(){ const char* fichierP = "log.bak"; if (unlink(fichierP) == -1) { if (errno==EACCES) { cout << "L'accès au fichier : "
<< fichierP << " est interdit" << endl; } else if (errno == ENOENT) { cout << "Le fichier ou le chemin d'acces"
<< " est introuvable" << endl; } }}
Département d’informatique et de génie logiciel
15
Problème important :• approche non compatible avec une architecture multi-tâche.
On doit protéger l'accès à cette variable globale...• On peut perdre de l'information si deux erreurs se produisent coup sur coup. La première erreur est écrasée par la seconde
potentiellement on peut mal interpréter la signification de l'erreur.
Département d’informatique et de génie logiciel
16
• Ignorer l'erreur
Prendre la décision de ne rien faire en cas de demande erronée peut parfois être la seule solution «raisonnable».
• Beaucoup de fonctions de la librairie standard ont un comportement «non défini» lors d'appel invalide.
• Que ce passe-t-il si on tente d'accéder un vecteur en dehors de ses limites ? (On ne sait pas !!!)
Ce style de programmation n'est pas à favoriser car il peut masquer des erreurs importantes.
Département d’informatique et de génie logiciel
17
• Imprimer un message d'erreur
Imprimer un message d'erreur décrivant l'erreur :• est acceptable pour un petit programme en phase de
débogage.• est inacceptable pour un logiciel commercial.
L'utilisateur ne devrait voir que des messages qui ont du sens pour lui et sur lesquels il peut prendre action.
Exemple :• si on l'avertit que le disque est plein, il peut effacer des fichiers
pour libérer de l'espace et poursuivre.
Département d’informatique et de génie logiciel
18
• Arrêter le programme
En phase de développement, • il est tout à fait acceptable d'arrêter le programme ou d'offrir de démarrer le débuggeur à l'endroit de l'erreur.
Pour un produit commercial, ce n'est pas acceptable.
• L'usager peut avoir travaillé plusieurs minutes (heures) avant de perdre son travail (...)
• Au minimum, il faut enregistrer les documents modifiés sur disque et enlever les fichiers temporaires.
Département d’informatique et de génie logiciel
19
• Lancer une exception
Les exceptions ont été ajoutées dans beaucoup de langages OO dont le C++.
Le mécanisme des exceptions est un moyen sûr et pratique :• pour lancer des exceptions sur le site de l'erreur.• transférer le contrôle à une autre partie du code qui pourra gérer
la situation avec compétence.Exemple :• «Incapable d'écrire ces bytes» pourrait être devenir «Disque
plein» à un niveau supérieur.
Département d’informatique et de génie logiciel
20
Synthèse
Erreurs• • • •
Réactions aux erreurs• • • • • •
Département d’informatique et de génie logiciel
21
ExceptionsLancer une exception
Lorsque se produit une erreur qui ne peut être prise en charge à l'endroit de sa détection,
une exception peut être lancée avec la commande throw :throw e;
où e peut être n'importe quoi : un entier, une string, ou beaucoup mieux, un objet.throw "Division par zéro";throw ERR_DIVISION_ZERO;throw DivParZeroException();
Département d’informatique et de génie logiciel
22
• Lancer une exception
Il est préférable d'utiliser les objets pour représenter les exceptions :
• utile pour spécifier le type de l'exception auquel on fait face ;
• permet de définir des sites d'interception basés sur le type d'exception ;
• permet de transporter de l'information dans l'objet du site de l'erreur jusqu'au site d'interception de l'exception.
Département d’informatique et de génie logiciel
23
• Une fonction ne retourne pas normalement
Lorsqu'une fonction lance une exception, le mécanisme veut que le système se mette immédiatement
à la recherche d'un site d'interception pour cette exception.La fonction ne retourne pas normalement,
• l'exécution de la fonction se termine immédiatement • l'exécution est transférée au site d'interception le plus proche
(pour cette exception).// --- lance DivParZeroExceptiondouble r = divise (3, 0);// --- Ne sera pas exécutécout << "Résultat: " << r << endl;
Département d’informatique et de génie logiciel
24
• Gérer une exception
Les sites d'interception des exceptions sont spécifiés à l'aide de blocs try-catch.try{ // code pouvant lancer une exception}catch (Type-exception e){ // e contient de l'information sur // l'exception. // code de gestion de l'exception}
Département d’informatique et de génie logiciel
25
double divise (int d, int n){
if (n==0) throw DivParZeroException(); return (double)d/n;}
try{ // --- lance DivParZeroException double r = divise (3, 0); cout << "Résultat: " << r << endl;}catch (DivParZeroException& e){ // --- Traitement de l'exception}
Département d’informatique et de génie logiciel
26
Le mécanisme peut sembler un peu lourd si on veut l'utiliser pour vérifier chaque appel de fonction comme :try{ double n = pile.pop();}catch (ContratException& e){ ...}
Département d’informatique et de génie logiciel
27
• Gérer une exception : résumé
Les exceptions sont utiles pour gérer des erreurs pouvant se produire n'importe où dans un sous-système.
Le transfert de contrôle du point de détection de l'erreur à un point de gestion compétent permet de mieux gérer les erreurs.
Ne pas être capable d'écrire un entier dans une stream (point de détection de l'erreur) devient détection d'une disquette pleine (sur le site de gestion de l'exception).
à ce niveau d'intervention, on peut interagir avec l'utilisateur dans des termes compréhensibles pour lui.
Département d’informatique et de génie logiciel
28
• Hiérarchie d'exceptions
La gestion des exceptions est basée sur le type d'exception (la classe),
• construire de petites classes appartenant à une hiérarchie.
La librairie standard du C++ a déjà mis en place un certain nombre d'exceptions.
La théorie du contrat définit des exceptions qui sont attachées à cette hiérarchie
• Du côté logic_error, i.e. erreur de programmation. • Du côté runtime_error par contre, il s'agit d'exception pouvant
toujours se produire.
Département d’informatique et de génie logiciel
29
• Classes définies dans la librairie standard
std::exception
std::logic_error std::runtime_error
std::domain_error
std::invalid_argument
std::length_error
std::out_of_range
std::overflow_error
std::underflow_error
std::range_error
Département d’informatique et de génie logiciel
30
• Gérer plus d'une exception
À partir d'un bloc try-catch, on peut gérer plusieurs exceptions à la fois :try{ // Code pouvant lancer des exceptions}catch (overflow_error& o){ // Gère des exceptions d'overflow}catch (underflow_error& u){ // Gère des exceptions d'underflow}
Département d’informatique et de génie logiciel
31
Si le code dans le bloc try génère une exception de type overflow_error ou underflow_error,
• le traitement correspondant est activé.
Si une exception d'un type différent est lancée, • elle doit être gérée ailleurs sur un site d'interception du bon
type.Si un tel site n'existe pas, le programme s'arrêtera en donnant
une erreur du type "Unhandle exception".
Département d’informatique et de génie logiciel
32
• Classes d'exception de contrat
std::logic_error
ContratException
m_ligne : intm_fichier : stringm_expression : string
reqTexteException() : string
InvariantException AssertionExceptionPostconditionExceptionPreconditionException
Département d’informatique et de génie logiciel
33
• Hiérarchie d'exceptions de contrat
Si on veut gérer toutes les exceptions de contrat, • mentionner catch (ContratException& e)
• toutes les exceptions de contrat : precondition, postcondition, invariant et assertion seront attrapées.
Si on veut gérer seulement les préconditions, • mentionner :catch (PreconditionException &e).
On pourrait gérer toutes les erreurs de programmation en mentionnant :catch (logic_error& e)
Département d’informatique et de génie logiciel
34
• Attraper toutes les exceptions et relancer
À l'occasion, nous voulons attraper toutes les exceptions (sans exception!!) qui passent à un endroit donné :
• pour faire une action protectrice• pour faire un nettoyage quelconque.
try{ // code}catch (...){ // Gestion de n'importe quelle exception throw; // Relance l'exception}
Département d’informatique et de génie logiciel
35
L'énoncé catch(...) avec les 3 petits points permet de gérer n'importe quel type d'exception.
L'énoncé throw sans argument dans un bloc catch permet de relancer l'exception courante de nouveau.
De fait, on doit toujours relancer une exception qu'on ne sait pas comment gérer (quoiqu'il aurait été préférable de ne pas l'avoir interceptée).
Une exception non interceptée arrête le programme.
Département d’informatique et de génie logiciel
36
• La pile d'appel
Gestion de la pile d'appel par le mécanisme des exceptions.Le flot linéaire d'exécution des instructions ne s'applique
plus lorsque qu'une exception est lancée.Au moment où une exception se produit, le contrôle passe
au site d'interception le plus proche pour cette exception.Tous les objets entre l'énoncé throw et l'énoncé catch
seront détruits et leur destructeur est appelé.Normalement les objets sur la pile sont détruits lorsque
l'exécution du programme atteint la fin d'un bloc ou d'une fonction.
Département d’informatique et de génie logiciel
37
Le mécanisme des exceptions garantit que tous les destructeurs des objets sur la pile seront appelés.après avoir lancé une exception et l'avoir récupéré, on peut continuer l'exécution.
Gérer les ressources de façon cohérente en fonction de cette nouvelle réalité.
point du catch
point du throw
main()
f1()
f2()
f3()
f4()
Département d’informatique et de génie logiciel
38
• Gestion des ressources
La possibilité qu'une exception puisse être lancée et qu'on ne puisse plus compter sur le flot linéaire d'exécution ajoute une préoccupation :
• Sommes-nous «exception-safe» ?
Exemples:
FILE* fichierP = fopen("input.dat");foo(fichierP); // peut lancer une exceptionfclose(fichierP); // peut ne jamais être exécuté
Employe* eP = new Employe();foo(eP); // peut lancer une exceptiondelete eP; // peut ne jamais être libérée
Département d’informatique et de génie logiciel
39
FILE* fP = fopen ("input.dat");try{ foo (fP);}catch (...){ fclose (fP); throw;}fclose (fP);
Employe* eP = new Employe();try{ foo (eP);}catch (...){ delete eP; throw;}delete eP;
Attraper toutes les exceptions, fermer le fichier ou libérer la mémoire et relancer l'exception est techniquement correct.
Appliqué à grande échelle, la viedu programmeur deviendrait pirequ'avant...
Département d’informatique et de génie logiciel
40
Structurer le code pour bénéficier de la gestion automatique des ressources en utilisant les constructeurs et les destructeurs des classes.
En utilisant une variable locale de type ifstream, on ouvre le fichier par le constructeur et le fichier est fermé par le destructeur :ifstream fs("input.dat");foo (fs);
Le fichier sera fermé lorsque le programme sera à la recherche d'un site d'interception pour une exception et que tous objets seront désalloués.
Département d’informatique et de génie logiciel
41
Même problème avec la mémoire allouée sur le monceau. On ne doit pas conserver de pointeur comme variable d'une
fonction. La classe auto_ptr<> du standard permet de conserver les
pointeurs dans des classes dont le destructeur gère la désallocation.
#include <memory>#include "Employe.h"using namespace std;- Pointeur sur la pile dans une fonctionEmploye* eP = new Employe("Yves");- Pointeur comme attribut d'un objetauto_ptr<Employe> pstr(new Employe("Yves"));
Département d’informatique et de génie logiciel
42
• Quelles exceptions lancer ?
Une exception non gérée résulte en un programme arrêté, • il est vital que le code minimise le nombre d'exceptions lancées
et que celles-ci soient clairement documentées.Ne jamais se servir des exceptions pour retourner des
résultats de calcul. • on peut ne pas tenir compte du type de retour d'une méthode
sans péril. ce n'est pas le cas avec une exception --> arrêt immédiat du programme.
Département d’informatique et de génie logiciel
43
Synthèse
Exception• • Lancer:• Attraper:
Simple:Multiple:Tous:
• Objets: