Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parBADR EN-NOUKH Modifié depuis plus de 5 années
1
1 Exception && Structure dynamique Exception && Structure dynamique Mohammed OUANAN
2
2 Gestion des exceptions Exception : Interruption de l’exécution d’un programme suite à un événement particulier Rupture de séquence déclenchée par une instruction throw(expression typée) Déclenchement d’une exception montée dans la pile d’appel des fonctions jusqu’à ce qu’elle soit attrapée sinon sortie de programme. Caractérisation de chaque exception par un type et le choix du bon gestionnaire d’exceptions Gestion des exceptions gestion simplifiée et plus sûre des erreurs
3
3 Principe général Le principe général des exceptions est le suivant: on crée des zones où l'ordinateur va essayer le code en sachant qu'une erreur peut survenir;// dans le bloc try{} si une erreur survient, on la signale en lançant un objet qui contient des informations sur l'erreur ; //avec throw à l'endroit où l'on souhaite gérer les erreurs survenues, on attrape l'objet et on gère l'erreur.//dans le bloc catch(){}
4
4 Les trois mot-clés en détail Les mot-clés du C++ qui correspondent à ces actions sont les suivants : try{...} (en français essaye) signale une portion de code où une erreur peut survenir ; throw (en français lance) signale l'erreur en lançant un objet ; catch(...){...} (en français attrape) introduit la portion de code qui récupère l'objet et gère l'erreur.
5
5 Les trois mot-clés en détail Commençons par try, il est très simple d'utilisation. Il permet d'introduire un bloc sensible aux exceptions, c'est-à-dire qu'on indique au compilateur qu'une certaine portion du code source pourrait lancer un objet On l'utilise comme ceci : try{ // Du code qui pourrait créer une erreur. } Entre les accolades du bloc try on peut trouver n'importe quelle instruction C++, notamment un autre bloc try.
6
6 Les trois mot-clés en détail Le mot-clé throw est lui aussi très simple d'utilisation. C'est grâce à lui qu'on lance l’exception. La syntaxe est la suivante : throw expression On peut lancer n'importe quoi comme objet, par exemple un int qui correspond au numéro de l'erreur ou un string contenant le texte de l'erreur. On verra plus loin un type d'objet particulièrement utile pour les erreurs. Remarque: throw peut se trouver n'importe où dans le code mais, s'il n'est pas dans un bloc try, l'erreur ne pourra pas être rattrapée et le programme plantera.
7
7 Les trois mot-clés en détail le mot-clé catch: permet de créer un bloc de gestion d'une exception survenue. Il faut créer un bloc catch par type d'objet lancé. Chaque bloc try doit obligatoirement être suivi d'un bloc catch. Inversement, tout bloc catch doit être précédé d'un bloc try ou d'un autre bloc catch. La syntaxe est la suivante : catch (type const& e){...} On attrape les exceptions par référence constante (d'où la présence du &) et pas par valeur, ceci afin d'éviter une copie et de préserver le polymorphisme de l'objet reçu.
8
8 Exemple int division(int a, int b){ return a/b;} Nous savons qu'une erreur peut survenir si b vaut 0, il faut donc lancer une exception dans ce cas. On va choisi, arbitrairement, de lancer une chaîne de caractères. C'est néanmoins un choix intéressant, puisque l'on peut ainsi décrire le problème survenu. int division(int a,int b) {if(b == 0) throw string("ERREUR : Division par zéro !"); else return a/b;} un throw doit toujours se trouver dans un bloc try qui doit lui-même être suivi d'un bloc catch. Cela donne la structure suivante :
9
9 Il ne reste plus alors qu'à gérer l'erreur, c'est-à-dire par exemple afficher un message d'erreur Cela donne le résultat suivant : Cette manière de faire est correcte. En effet, la fonction est susceptible d'écrire dans la console alors que ce n'est pas son rôle. De plus, le programme continue alors qu'une erreur est survenue. Le mieux à faire serait alors de lancer l'exception dans la fonction et de récupérer l'erreur, si elle se produit, dans le main. De cette manière, celui qui appelle la fonction a conscience qu'une erreur s'est produite.
10
10 Exemple Remarquez que le throw ne se trouve pas directement à l'intérieur du bloc try mais qu'il se trouve à l'intérieur d'une fonction qui est appelée, elle, dans un bloc try. Le else dans la fonction division n'est pas nécessaire puisque si l'exception est levée, le reste du code jusqu'au catch n'est pas exécuté. Cette fois, le programme ne plante plus et la fonction n'a plus d'effet de bord. C'est la meilleure solution.
11
11 Gestion d’exception #include #include // Ancien : pour exit class vect { int nelem ; int * adr ; public : vect (int n) { adr = new int [nelem = n] ;} ~vect () { delete adr ; } int & operator [] (int) ; } ; // déclaration et définition d'une classe vect_limite class vect_limite { // vide pour l'instant} ; int & vect::operator [] (int i) { if (i =nelem) { vect_limite e ; throw (e) ;} return adr [i] ; } Si le paramètre i n’est pas correct, déclenchement d’une exception
12
12 Gestion d’exception // Programme exemple d’interception // de l’exception vect_limite int main () { try // Zone de surveillance { vect v(10) ; v[11] = 5 ; // Ici déclenchement d’une exception // car l’indice est trop grand } catch (vect_limite e) // Traitement de l’exception { cout << "exception limite" << endl ; exit (-1) ; // Sortie du programme } exception limite
13
13 Gestion des exceptions //déclaration-définition des deux classes pour les exceptions class vect_limite { public: int hors; // valeur indice hors limites (public) vect_limite (int i) {hors = i;} // constructeur }; class vect_creation { public: int nb; // nombre éléments demandes (public) vect_creation (int i) {nb = i;} // constructeur }; // Redéfinition du constructeur de la classe vect vect::vect (int n) { if (n <= 0) { vect_creation c(n); // anomalie throw c; } adr = new int [nelem = n]; // construction si n est correct }
14
14 Gestion d’exceptions int & vect::operator [] (int i) { if (i nelem) { vect_limite l(i); // anomalie throw l; } return adr[i];// fonctionnement normal } // Programme exemple pour intercepter les exceptions int main() { try // Zone de surveillance { vect v(-3);//provoque l'exception vect_creation v[11] = 5;//provoquerait l'exception vect_limite } catch(vect_limite l)//Traitement de l’exception vect_limite { cout<< "exception indice"<<l.hors<<" hors limites"<< endl; exit (-1); } catch(vect_creation c) // Traitement de l’exception vect_creation { cout<< "exception creation vect nb elem = "<<c.nb<<endl; exit (-1) ; }} exception creation vect nb elem = -3
15
15 Gestion d’exception Fichier en-tête bibliothèque standard fournissant des classes d’exceptions Plusieurs exceptions standard susceptibles d’être déclenchées par une fonction ou un opérateur de la bibliothèque standard Ex. classe bad_alloc en cas d’échec d’allocation mémoire par new vect::vect (int n) // Constructeur de la classe vect { adr = new int [nelem = n] ;} int main () { try { vect v(-3) ;} catch (bad_alloc) // Si le new s’est mal passé {cout << " exception création vect avec un mauvaise nombre d'éléments "<< endl; exit (-1) ; } En cas d’exception non gérée appel automatique à terminate() qui exécute abort();
16
16 Gestion d’exception La classe exception est la classe de base de toutes les exceptions lancées par la bibliothèque standard. Elle est aussi spécialement pensée pour qu'on puisse la dériver afin de réaliser notre propre type d'exception. La définition de cette classe est class exception { public: exception () throw(); exception (const exception&) throw(); exception& operator= (const exception&) throw(); virtual ~exception() throw(); virtual const char* what() const throw(); } ; Classes derivées de exception: bad_alloc, bad_cast, bad_exception, bad_typeid …
17
17 La bibliothèque standard peut lancer 5 types d'exceptions différents résumés dans le tableau suivant :
18
18 Gestion d’exception Classe exception ayant une méthode virtuelle what() affichant une chaîne de caractères expliquant l’exception. int main () { try { vect v(-3) ;} catch (bad_alloc b) { // Appel de la méthode what pour l’exception bad_alloc cout << b.what() << endl ; exit (-1) ; } } Possibilité de dériver ses propres classes de la classe exception class mon_exception : public exception { public : mon_exception (char * texte) { ad_texte = texte ; } const char * what() const throw() { return ad_texte ; } private : char * ad_texte ; } ;
19
19 Gestion d’exception int main() { try { cout << "bloc try 1" << endl; throw mon_exception ("premier type") ; } catch (exception & e) { cout << "exception : " << e.what() << endl; } try { cout << "bloc try 2" << endl; throw mon_exception ("deuxieme type") ; } catch (exception & e) { cout << "exception : " << e.what() << endl; } bloc try 1 exception : premier type bloc try 2 exception : deuxieme type
20
20 Gestion d’exceptions Possibilité d’intercepter une exception dans une méthode (ex. constructeur) : class D { int id; public: D(int i) {if (i<0)throw (-1); else id=i;} }; class C { D d; public: C(int i=0) try : d(i) {} catch (int) { // traitement exception } }; Une exception interrompt l’exécution normale du code, mais avant de passer la main au catch, tous les objets locaux sont détruits!
21
21 Les conteneurs La librairie standard implémente un ensemble de structures de données couramment utilisées, ainsi que des algorithmes s’appliquant à elles. Il s’agit des classes conteneur. Il existe trois grandes catégories de conteneurs : les séquences élémentaires (vector, list, deque), les utilisations spécialisées des séquences élémentaires (queue, stack), les conteneurs associatifs (set, map).
22
22 La classe vector La classe vector permet de gérer une donnée qui s’apparente à un tableau. En outre, elle possède des caractéristiques similaires, telles que l’indexation initiale à 0. #include using namespace std; int main() { vector monVecteur(5); // vecteur de 5 éléments for( int i=0; i<monVecteur.size(); i++ ) monVecteur[i] = i; for( i=0; i<monVecteur.size(); i++ )cout << monVecteur[i] << endl; const int nAReserver(10); monVecteur.reserve( nAReserver ); // réservation cout<< monVecteur.capacity()<<" "<<monVecteur.size()<< endl; monVecteur[5] = 5; cout << monVecteur.capacity()<<" "<<monVecteur.size()<<endl; monVecteur.resize(6); // redimensionnement monVecteur[5] = 5; cout << monVecteur.capacity()<<" "<<monVecteur.size() << endl; monVecteur.front() = -1; // accès au premier élément monVecteur.back() = -2; // accès au dernier élément monVecteur.push_back(28); // ajoute élément fin de liste monVecteur.pop_back( ); // retire élément fin de liste for( i=0; i<monVecteur.size();i++ ) cout << monVecteur[i] << endl; return 0; }
23
23 La classe list La classe list implémente une gestion de liste chaînée classique. Elle possède en grande partie les mêmes fonctionnalités que la classe vector, à quelques détails près bien entendu. Par exemple, il est possible de détruire un élément à n’importe quelle place, ou encore, ne possède pas d’opérateur crochets (operator[]). Enfin, par essence même, un objet défini par cette structure prendra plus de place en mémoire que son équivalent utilisant la classe vector. Exemple d’utilisation :
24
24 Exemple class list #include using namespace std; int main() { list maListe( 5 ); // liste de 5 éléments maListe.front() = -1; // accès au premier élément maListe.back() = -2; // accès au dernier élément maListe.push_back( 28 ); // ajoute élément en queue maListe.pop_back( ); // retire élément en queue LA LIBRAIRIE STANDARD 55 return 0; }
25
25 Les "itérateurs" Les itérateurs sont parmi les éléments les plus importants des conteneurs, dans la mesure où ils sont utilisés en permanence lorsqu’on manipule ces dernières, que ce soit en lecture ou en écriture. Pour faire simple, un itérateur est une sorte de pointeur sur un élément d’un conteneur, liste ou vecteur par exemple. Car, s’il demeure toujours possible d’accéder aux données des conteneurs par une indexation classique dans certains cas, vous verrez à l’usage qu’il est impossible ou pour le moins malaisé, pour certaines opérations telles que les insertions.
26
26 Exemple de parcours d’un conteneur avec un iterateur #include #include int main() { vector v; v.push_back(8); v.push_back(12) ; v.push_back(3); vector ::const_iterator p; for (p =v.begin(); p !=v.end();p++) { cout<<*p<<" ; "; } } // affichage : 8 ; 12 ; 3 ;
27
27 Exemple d'utilisation de list #include int main() { list l1; l1.push_front(1); // l1 : 1 l1.push_front(2); // l1 : 2 1 l1.push_back(4); // l1 : 2 1 4 l1.push_back(3); // l1 : 2 1 4 3 l1.sort(); // l1 : 1 2 3 4 int tab[4]={2, 6, 4, 8}; list l2; l2.insert(l2.begin(),tab,tab+4); // l2 : 2 6 4 8 l1.splice(l1.end(),l2); // l1 : 1 2 3 4 2 6 4 8 l1.sort(); // l1 : 1 2 2 3 4 4 6 8 l1.remove(4); // l1 : 1 2 2 3 6 8 l1.unique(); // l1 : 1 2 3 6 8 }
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.