08 Gestion des exceptions .pdf



Nom original: 08-Gestion_des_exceptions.pdf

Ce document au format PDF 1.5 a été généré par LaTeX with Beamer class version 3.33 / pdfTeX-1.40.14, et a été envoyé sur fichier-pdf.fr le 18/01/2017 à 08:36, depuis l'adresse IP 194.199.x.x. La présente page de téléchargement du fichier a été vue 541 fois.
Taille du document: 418 Ko (58 pages).
Confidentialité: fichier public


Aperçu du document


INFO0402 : Méthodes de programmation
orientée objet
Gestion des exceptions

Pascal Mignot

2015-2016

INFO0402 :
Méthodes de
programmation
orientée objet

Introduction

Pascal Mignot

Introduction
Gestion
classique

La gestion des erreurs est une des tâches qu’un programme doit
nécessairement effectuer afin de :

Bases

• apporter une réponse aux cas exceptionnels,

Exception STL

• fournir des informations sur le problème,

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

2/ 58

• ne pas laisser l’erreur se propager

Afin de répondre à cette problématique, nous aborderons :
• les méthodes classiques de gestion des erreurs,
• la gestion des exceptions (méthode C++ ) et les méthodes à

adopter afin de les utiliser correctement.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

Introduction
Les exceptions sont un mécanisme du langage pour gérer les situations
exceptionnelles (=anormales).
Par situation exceptionnelle, on entend :

• une condition d’erreur,
dans ce cas, la gestion d’exception permet de gérer les erreurs.

• un cas où le code ne peut pas réaliser ce qui lui a été demandé,
dans ce cas, la gestion d’exception permet de traiter des cas
(normalement) exceptionnels.
Comportement d’un code :

• un code qui rencontre une erreur qu’il n’est pas capable de gérer lance
une exception,

• l’exception propage l’information depuis l’endroit où l’erreur est détecté
jusqu’au point où elle sera gérée,

• un code qui gère l’erreur attrape l’exception, et effectue le traitement
nécessaire pour gérer l’erreur.
L’exception fournit un moyen pratique par lequel on sépare la détection d’erreur

3/ 58

de la gestion de l’erreur.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Généralité
Gestion d’erreur C

Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

4/ 58

Gestion classique
Approche traditionnelle de la gestion d’erreur :
1 terminaison : s’il y a une erreur, terminer le programme.

analyse : trop draconien.
2 le fonction dans laquelle l’erreur se produit retourne un code d’erreur

L’appelant de la fonction doit vérifier le code retourné.
analyse :
• les erreurs sont ignorés par défaut (i.e. des actions explicites sont
requises pour vérifier si une erreur a eu lieu),
• si l’appelant oublie de vérifier le code de retour, l’erreur peut ne pas
être détectée.
• le code peut devenir parsemé de vérifications de code de retour, ce
qui peut affecter la lisibilité et la maintenabilité du code.
3 appeler un gestionnaire d’erreur (handler) si une erreur est détectée

analyse : il peut être impossible (ou difficilement réalisable) de traiter
certaines erreurs (le handler peut ne pas avoir accès à l’ensemble des
informations pour passer l’erreur).

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Généralité
Gestion d’erreur C

Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

5/ 58

Gestion classique
Exemple 1 : terminaison
void f u n ( ) { . . .
i f ( error_condition ) e x i t ( −1);
... }

Exemple 2 : code d’erreur
/ / error .h
typedef u i n t 3 2 _ t
Status ;
# define SUCCESS
0x80000000 / / MSB à 1
# define SUCCEEDED( x ) ( x & 0x80000000 )
# define FAILED ( x )
( ! SUCCEEDED( x ) )
# define EUNKNOWN_FILE 0x00040054 / / 0004=mod,0054= e r r .
# include " e r r o r . h "
/ / f a i t s u i v r e l e code d ’ e r r e u r
ErrorCode fun1 ( . . . ) { . . .
ErrorCode fun2 ( . . . ) { . . .
i f ( error_condition )
S t a t u s s = fun1 ( . . . ) ;
r e t u r n EUNKNOWN_FILE ;
i f ( FAILED ( s ) ) r e t u r n s ;
. . . r e t u r n SUCCESS; }
. . . r e t u r n SUCCESS; }
/ / t r a i t e m e n t de l ’ e r r e u r
S t a t u s s= fun2 ( . . . ) ;
i f ( FAILED ( s ) ) {
/ / g e s t i o n de l ’ e r r e u r
}

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Généralité
Gestion d’erreur C

Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

6/ 58

Gestion classique
Exemple 3 : gestionnaire d’erreur
/ / p o i n t e u r de f o n c t i o n
typedef i n t p t _ e r r o r _ h a n d l e r ( const char * , const char * ,
i n t , i n t , const char * ) ;
/ / gestionnaire d ’ erreur
i n t m y_ er ro r_ ha nd l er ( const char * f i l e , const char * f u n c t i o n ,
i n t l i n e , i n t code , const char * msg ) {
...
}
/ / d é f i n i t i o n du g e s t i o n n a i r e d ’ e r r e u r
pt_error_handler
* h a n d l e r = m y_ e rr or _h an dl er ;
/ / macro pour e r r o r
# define E r r o r ( code , reason ) ( * h a n d l e r ) ( __FILE__ , __FUNCTION__ , \
__LINE__ , code , reason )
// utilisation
i n t fun ( i n t n ) {
. . . i f ( e r r n o ==EDOM) E r r o r (EDOM, " argument o u t o f domain " ) ;
...
}

INFO0402 :
Méthodes de
programmation
orientée objet

Gestion d’erreur C

Pascal Mignot

De nombreuses fonctions de la bibliothèque C utilisent errno pour retourner
leurs erreurs.
Introduction
Gestion
classique
Généralité
Gestion d’erreur C

Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

7/ 58

On en rappelle le fonctionnement :

• errno est une variable globale entière,
• initialisée à 0 au lancement du programme (0 signifie pas d’erreur),
• lorsqu’une erreur survient, sa valeur est changée en un code
correspondant à l’erreur rencontrée.

• les codes d’erreur générés peuvent être trouvés dans la documentation
de la fonction de la bibliothèque C utilisée (voir errno.h).
Conséquences :

• sa valeur correspond à la dernière erreur rencontrée,
• charge à l’utilisateur de la réinitialiser (à 0).
• si errno est initialisée à 0 avant un bloc de code, alors
• si errno = 0, alors aucune erreur n’a été rencontrée,
• si errno , 0, alors au moins une erreur s’est produite dans le bloc,
et le code de cette erreur est celui de errno.

INFO0402 :
Méthodes de
programmation
orientée objet

Gestion d’erreur C

Pascal Mignot

Fonctions utiles :
Introduction
Gestion
classique
Généralité
Gestion d’erreur C

Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

8/ 58

• char* std::strerror(int err) renvoit la chaine de caractères
associées au code d’erreur contenu dans l’entier err.

• std::perror(const char *msg) : affiche sur std::stderr le
message d’erreur associé au contenu de errno (i.e. strerror(errno))
précédé de msg.
Exemple :
double not_a_number = s t d : : l o g ( − 1 . 0 ) ;
i f ( e r r n o ) s t d : : p e r r o r ( " l o g ( − 1) f a i l e d " ) ;
Sortie : log(-1) failed: Numerical argument out of domain
Notes :

• A partir du C++
11 , cette variable devient locale au thread (ouf !).
• inclure <cerrno>
• il existe des classes standards (basées sur std::error_category) qui
permettent de gérer ses propres codes d’erreur.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Gestion par exception
La gestion d’erreur standard en C++ s’effectue avec les exceptions.
Gestion des erreurs avec les exceptions :

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

1 un bloc try contient le code qui pouvant engendrer une erreur.

aucun traitement d’erreur n’a lieu dans ce bloc.
2 si une condition d’erreur est rencontrée dans le bloc, alors throw lance

une exception.
3 le bloc try est suivi par un bloc catch qui effectue le traitement associé

à l’exception (contient le handler de l’exception).
Conséquences :

• le handler de l’exception peut être dans une fonction différente de celle
qui l’a lancée (propagation dans les fonctions appelantes),

• les parties de code qui ne génèrent pas d’erreur sont simples, puisqu’il
n’y a pas besoin de tester explicitement les erreurs.

• les cas d’erreurs ont peu de chance de ne pas être détectée, puisqu’une
exception lancée mais non traitée provoque la terminaison du
programme.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Gestion par exception
Fonctionnement élémentaire :

• Le code qui peut lancer une exception est placé dans un bloc try,
Introduction
Gestion
classique

• Le code qui peut gérer l’exception est placé dans un bloc catch,
• Pour un même bloc try-catch,

Bases

• il peut avoir plusieurs clauses catch,
• les clauses catch sont testés dans l’ordre spécifié, et seulement la
première clause ayant un type correspondant au throw est utilisée
(upcasting compris).
• la clause catch(...) peut être utilisée pour capturer toute
exception non encore gérée. Dangeureux :
• on ne connait pas l’exception capturée,
• devrait être remplacée par catch(std::exception&) (voir
partie sur les exceptions standards).

Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Exemple :
try {
catch
catch
catch

/ * code q u i peut l a n c e r une e x c e p t i o n * / }
( const s t d : : l o g i c _ e r r o r & e ) { / * e r r e u r s l o g i q u e s * /
}
( const s t d : : r u n t i m e _ e r r o r& e ) { / * e r r e u r s d ’ e x é c u t i o n * / }
( . . . ) { / * toutes les autres erreurs * / }

INFO0402 :
Méthodes de
programmation
orientée objet

Gestion par exception

Pascal Mignot

Qu’est-ce-qui est lancé lorsqu’une exception est lancée ?
Introduction

• les exceptions sont des objets :

Gestion
classique

• le type de l’erreur est indiqué par le type de l’objet.

Bases

• la valeur de l’objet est utilisée pour fournir les détails sur l’occurence

Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

particulière de l’erreur associée,

• le type de l’objet peut être être soit issu de la bibliothèque standard, soit
fourni par l’utilisateur.
Conséquences :

• c’est l’objet exception lui-même qui est propagé de la partie du code qui
génère l’exception (throw) vers la partie du code qui le gère (catch).

• c’est le type de l’exception qui permet de déterminer quel est le handler
(catch) qui traitera l’exception.

• le lancement d’une exception interrompt le déroulement normal du code.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Gestion par exception
Règles générales :

• lancer l’exception par valeur,
et non par pointeur ou référence : l’objet auquel il faut référence peut ne
plus exister lorsqu’il sera traité.

Introduction
Gestion
classique

• récupérer l’exception par référence dans un catch
• éviter la copie, qui pourrait générer aussi une exception,
• évite l’object slicing (voir le cours sur l’héritage) ou la copie.
• permet à l’objet d’être modifié, afin de lever une exception modifiée,

Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Pour un throw A(), quels catches ?

• un catch ne peut pas être une référence à une rvalue, une classe
abstraite, un type incomplet ou un pointeur vers un type incomplet.

• catch(A) (par valeur) possible mais déconseillé,
• catch(A&) ou catch(const A&)
• catch(B) aussi possible si upcasting possible (i.e. B est une classe de





base de A), mais déconseillé car par valeur.
catch(B&) ou catch(const B&) sous la même condition,
catch(void*) si A est un pointeur (capture tout pointeur),
également en version volatile,

catch(...)

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Exception personnalisée
Il est recommandé pour un module de disposer de sa propre
classe d’exception
si possible héritée d’une classe d’exception standard (voir
exception de la STL).
voir cette partie.
Cela réduit la vraisemblance qu’une exception générée par un
module soit captée par un autre de manière conflictuelle.
Si un throw lancé est un objet, alors les constructeurs par
copie/déplacement et le destructeur doivent être
accessibles (c’est le moyen avec lequel l’exception est
propagée) :
• throw x; initialise un objet temporaire du type de x avec x.
• cet objet temporaire peut être copié/déplacé plusieurs fois

avant d’atteindre le handler qui le gère (catch du type de x).

INFO0402 :
Méthodes de
programmation
orientée objet

Gestion par exception

Pascal Mignot

Fonctionnement multi-niveau :
Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

• lorsqu’une exception est levée, la gestion de l’exception est transférée à
la clause catch du bloc try le plus récemment traversé (et toujours en
cours d’exécution) qui permet de traiter l’exception.
si aucune clause adaptée n’est trouvée, alors std::terminate() est
appelé.

• lors du passage de l’exception à la clause, les destructeurs des objets
automatiquement construits dans le bloc try sont appelés dans l’ordre
inverse de leurs constructions (note : ce procédé s’appelle "stack
unwinding")
conséquence :
• ne seront détruits que les objets automatiques effectivement
construit au moment de l’exception (les suivants dans le bloc try
n’ayant pas encore été construits).
• ne jamais lancer d’exception dans un destructeur

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Gestion par exception
Exemple :
void fun3 ( . . . ) { . . . A a1 ; . . .
void fun2 ( . . . ) { . . . A a3 : . . .
void fun1 ( . . . ) { . . . A a5 : . . .
void f u n ( . . . ) {
t r y { . . . A a7 ; . . . fun1 ( ) ;
catch ( const i n t &x ) { . . .
}

throw 1 ; . . . A a2 ; . . . }
fun3 ( ) ; . . . A a4 ; . . . }
fun2 ( ) ; . . . A a6 ; . . . }
. . . A a8 ;

... }

}

Ce code fonctionne de la manière suivante :

Exception STL

• l’exception levée dans fun3, appel du destructeur de a1, pas de catch

Spécification
d’exception

• pas de catch dans fun2, appel du destructeur de a3, gestion

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

dans fun3, gestion transférée à l’appelant,
transférée à l’appelant,

• pas de catch dans fun1, appel du destructeur de a5, gestion
transférée à l’appelant,

• catch pouvant traiter l’exception, appel du destructeur de a7,
initialisation de x, et exécution du traitement.

INFO0402 :
Méthodes de
programmation
orientée objet

Gestion par exception

Pascal Mignot

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Remarque sur le stack unwinding :
si une exception est levée entre le moment où l’exception est
levée, et le moment où elle est traitée (par exemple, lors du
stack unwinding), alors le programme se termine
immédiatement (std::terminate()).
conséquence : ne jamais lever d’exception :
• dans un destructeur : il pourrait être lancé dans un stack
unwinding,
• dans le constructeur par copie/déplacement d’un objet
gérant des exceptions (effectué au moment du throw).

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Gestion par exception
Forwarding d’exception :

• il est possible de relancer une exception (éventuellement la même) dans
un catch.
la gestion de l’exception est alors transférée au bloc supérieur (voir
gestion multi-niveau).

• l’utilisation de la commande throw; (sans argument) dans un catch
permet de relancer l’exception (et donc de délèguer son traitement dans
un bloc catch supérieur)
Exemple :
try {
/ / lance l ’ exception std : : l e n g t h _ e r r o r
s t d : : s t r i n g ( " abc " ) . s u b s t r ( 1 0 ) ;
} catch ( const s t d : : e x c e p t i o n& e ) {
s t d : : c o u t << e . what ( ) << ’ \ n ’ ;
/ / r e l a n c e une e x c e p t i o n par c o p i e de e
/ / throw e ;
/ / r e l a n c e l ’ e x c e p t i o n reçue
throw ;
}

INFO0402 :
Méthodes de
programmation
orientée objet

Fonction Try-bloc

Pascal Mignot

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Une fonction try-bloc est obtenue lorsque qu’un try est placé
sur la totalité du corps d’une fonction
Elle capture les exceptions qui peuvent avoir lieu :
• lors de la construction des paramètres (i.e. avant l’exécution

de la fonction),
• lors de la destruction des variables locales (après l’accolade

fermante),
• dans un constructeur, lors de la construction des membres

et des objets de base,
• dans un destructeur, lors de la destruction des membres et

des objets de base (rappel : mauvaise idée de lancer une
exception dans un destructeur)

INFO0402 :
Méthodes de
programmation
orientée objet

Fonction Try-bloc

Pascal Mignot

Syntaxe :
Introduction

1

i n t fun ( . . . ) {
t r y { / * code de l a f o n c t i o n * / }
catch ( ? ) { . . . }
}

2

i n t fun ( . . . )
t r y { / * code de l a f o n c t i o n * / }
catch ( ? ) { . . . }

Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

à savoir :

• la totalité du code de la fonction est incluse dans le try-bloc,
• la fonction se termine au moment où le flux de contrôle atteint la fin du
catch block.
Différence entre les deux syntaxes : la syntaxe 1 permet d’effectuer un
return dans un catch, alors que la syntaxe 2 oblige le return à s’effectuer
dans le corps de la fonction.

INFO0402 :
Méthodes de
programmation
orientée objet

Fonction Try-bloc

Pascal Mignot

Introduction
Gestion
classique
Bases
Introduction
Fonctionnement
élémentaire
Rôle du type
Stack unwinding
Forwarding
d’exception
Fonction Try-bloc

Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées

Note : la version 2 de la fonction try-bloc peut être utilisée aussi dans
les constructeurs ou les destructeurs.
Exemple :
Foo : : Foo ( i n t a )
t r y : Base ( a ) , member ( a ) { . . . }
catch ( s t d : : e x c e p t i o n& ex ) { . . . }

Remarques : sur les portées
• tout paramètre de la fonction est aussi dans la portée du catch
dans le cas du constructeur ci-dessus, a est accessible dans le
catch.
• les variables locales du bloc try ne sont évidemment pas
accessible dans un catch.
• dans le cas de la version constructeur/destructeur, le catch ne
peut ni faire référence à la base, ni au membre.

INFO0402 :
Méthodes de
programmation
orientée objet

Exception de la bibliothèque standard

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Exceptions standards
Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

21/ 58

La STL fournit des types basiques d’exception. Toutes les
exceptions de la STL dérivent directement ou indirectement de la
classe std::exception (incluse dans <exception>).






logic_error : classe des erreurs logiques
runtime_error : erreur hors de portée du programme
bad_typeid : opérateur invalide pour l’opérateur typeid,
bad_cast : opération invalide pour un dynamic_cast,
bad_weak_ptr : opération invalide sur un std::weak_ptr
(C++
)
11
• bad_function_call : appel std::function sans fonction
définie (C++
)
11
• bad_alloc : erreur d’allocation mémoire (voir plus loin)
• bad_exception : mauvaise gestion des exceptions dans le
cas d’exception dynamique ou de pointeur d’exception.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases

Exception de la bibliothèque standard
Pour les allocations mémoires, deux types d’exceptions peuvent être levée :

• bad_alloc : erreur d’allocation mémoire (cas général)
• bad_array_new_length : spécialisation si l’erreur est liée à la taille
demandée (négative, dépassant la taille maximale de l’implémentation,
trop d’initialisations par rapport à la taille demandée) (C++
11 ))
On peut ainsi faire la différence entre une erreur d’allocation liée à l’absence
de mémoire et liée à une erreur d’utilisation de la fonction d’allocation.

Exception STL
Exceptions standards
Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

22/ 58

Exemple :
/ / e r r e u r d ’ u t i l i s a t i o n de l a f o n c t i o n d ’ a l l o c a t i o n
try {
i n t n e g a t i v e = − 1, s m a l l = 1 , l a r g e = INT_MAX ;
new i n t [ n e g a t i v e ] ;
/ / negative size
new i n t [ s m a l l ] { 1 , 2 , 3 } ;
/ / t o o many i n i t i a l i z e r s
new i n t [ l a r g e ] [ 1 0 0 0 0 0 0 ] ; / / t o o l a r g e
} catch ( const s t d : : bad_array_new_length &e ) {
s t d : : c o u t << e . what ( ) << ’ \ n ’ ;
}
/ / e r r e u r d ’ a l l o c a t i o n c a r p l u s de mémoire
try {
while ( t r u e ) { new i n t [100000000 u l ] ; }
} catch ( const s t d : : b a d _ a l l o c& e ) {
s t d : : c o u t << " A l l o c a t i o n f a i l e d : " << e . what ( ) << ’ \ n ’ ;
}

INFO0402 :
Méthodes de
programmation
orientée objet

Exception de la bibliothèque standard

Pascal Mignot

Introduction

Classe des exceptions logiques dans logic_error :

Gestion
classique

• invalid_argument : argument invalide

Bases

• domain_error : erreur de domaine (exemple : racine carrée

Exception STL
Exceptions standards
Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

23/ 58

d’un nombre négatif)
• length_error : longueur trop grande (exemple : resize

d’un vector plus grand que max_size)
• out_of_range : argument hors de l’intervalle autorisé

(exemple : vector::at à l’extérieur des bornes).
• future_error (C++
) : operation invalide sur le résultat d’une
11

opération asynchrone (voir std::future).

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Exceptions standards
Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

Exception de la bibliothèque standard
Classe des exceptions système dans runtime_error :

• range_error : le résultat d’un calcul ne peut être représenté dans le





type de destination,
overflow_error : erreur d’overflow arithmétique
underflow_error : erreur d’underflow arithmétique
regex_error : erreur de la bibliothèque d’expression régulière (C++
11 )
system_error : erreur issue du système d’exploitation, ou autre erreur
bas niveau (C++
11 )
• ios_base::failure : erreur issue de la bibliothèque iostream
(C++
11 )

Attention :

• les erreurs arithmétiques standards ne génèrent pas d’exception (i.e. tout
ce qui était déjà dans le C ne lance pas d’exception : il faut utiliser le
gestionnaire standard du C), ou utiliser une bibliothèque mathématique
alternative comme boost::math.

• même remarque pour system_error, les erreurs systèmes en question
sont par exemple celles issues de la bibliothèque thread du C++
11 .

• pas moyen d’attraper une erreur sérieuse (par exemple segmentation
fault) avec des exceptions.

24/ 58

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Exceptions standards
Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

25/ 58

Récupération d’une exception
Ces classes fonctionnent toutes de la manière suivante :
• le catch peut être effectué avec le type de l’exception elle-même,
ou tout type dont elle dérive.
Exemple :
std : : vector <int >
v;
try { v . at ( 4 ) ; }
/ / c a t c h par l ’ une de ces e x c e p t i o n s
/ / de l a p l u s s p é c i a l i s é e à l a p l u s g é n é r a l e
catch ( const s t d : : o ut _o f_ ra n ge &e ) { . . . }
catch ( const s t d : : l o g i c _ e r r o r &e ) { . . . }
catch ( const s t d : : e x c e p t i o n &e ) { . . . }

out_of_range dérive de logic_error, qui dérive de exception.
• la méthode what() sur toute classe dérivant de std::exception
retourne la cause de la levée de l’exception.
Dans l’exemple précédent, e.what() retourne
invalid vector<T> subscript.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Exceptions standards
Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

26/ 58

Exception utilisateur
Quelques règles de conceptions d’une classe de gestion d’exception :

• la faire dériver de std::exception : c’est une classe d’exception
raisonnable, et qui permet de capter l’ensemble des exceptions (i.e. sans
à avoir à utiliser catch(...)).

• il est prudent d’hériter virtuellement de std::exception afin d’éviter les
problèmes d’ambiguïté, au cas où une exception dériverait de bases
multiples qui ont une classe de base en commun.
si catch(std::exception const& e) avec un objet throw défini
comme indiqué, le compilateur ne sait pas alors vers quelle classe de
base résoudre.

• ne pas inclure d’objet dans une exception dont le constructeur par copie
ou dont les constructeurs de base/membre peut lancer une exception.
Exemple : i.e. de std::string

• le formatage du message fournit par what() prend de la mémoire, et
peut potentiellement lancer une exception : donc, protéger what() avec
un try-bloc (au cas où le formatage échoue).

• faire en sorte que la classe d’exception soit immunisée contre une
destruction double (en mettant à zéro les pointeurs), car certains
compilateurs détruisent occasionnellement les exceptions deux fois.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Exceptions
Avantages des exceptions :

• le code de gestion d’erreur peut être facilement séparé du code qui
génère l’erreur,

Introduction
Gestion
classique
Bases
Exception STL
Exceptions standards

• les exceptions peut facilement passer les informations d’erreur au travers
autant de niveaux de la pile d’appel que nécessaire afin d’atteindre le
code de gestion de l’exception,

• la transmission d’exception est gérée par le langage (pas de code
explicite requis)

Récupération
Exception utilisateur

Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

27/ 58

Désavantages des exceptions :

• écrire des codes qui se comportent correctement en cas d’exception
demande beaucoup de soin,

• s’il peut potentiellement être possible de ne pas avoir de coût d’exécution
lorsque des exceptions ne sont pas lancées, il y a toujours un coût
mémoire (pour stocker les informations nécessaires pour gérer le
changement de contexte dans la pile d’appel lorsqu’une exception est
levée),

• elles ne permettent pas de récupérer d’erreurs sérieuses (comme un
segmentation fault). Les solutions pour faire ceci dépendent de la
plateforme (Windows :SEH, Linux :récupérer SIGSEGV avec sigaction).

INFO0402 :
Méthodes de
programmation
orientée objet

Spécification d’exception

Pascal Mignot

Introduction
Gestion
classique

Les spécifications d’exception sont des mécanismes permettant
de restreindre le lancement d’exception dans certaines parties
du code.

Bases
Exception STL
Spécification
d’exception
Exception dynamique

noexcept
Spécificateur
Opérateur
Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
28/ 58

Deux moyens sont utilisés pour cela :
• les exceptions dynamiques qui permettent de spécifier

pour une fonction les exceptions qu’elle a le droit de lancer,
• noexcept qui permet d’indiquer qu’une fonction n’a pas le

droit de lancer d’exception.
La maitrise des spécifications d’exception est un mécanisme
important dans l’implémentation correcte des exceptions dans
un code C++ .

INFO0402 :
Méthodes de
programmation
orientée objet

Spécifications d’exception dynamique
Cette fonctionnalité est considérée comme obsolète et ne doit pas être utilisée.

Pascal Mignot

Introduction
Gestion
classique
Bases

Mécanisme permettant de spécifier la liste de tous les types d’exception qui
peuvent être lancées.
Exemple : / / f peut l a n c e r des e x c e p t i o n s de t y p e X ou Y
void f ( ) throw ( X , Y ) ;

Fonctionnement :

Exception STL

• à l’exécution de la fonction, lorsqu’une exception est lancée, son type est

Spécification
d’exception

comparé à l’ensemble de celles autorisées. Si elle ne l’est pas,
std::unexpected() est exécuté, sinon elle est effectivement lancée.
• set_unexpected( void (*)() ) permet de fixer la fonction qui sera
appelée par std::unexpected() (le défaut est std::terminate()).
• throw() est équivalent à noexcept.

Exception dynamique

noexcept
Spécificateur
Opérateur
Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
29/ 58

Remarques : (répétition) obsolète, ne doit plus être utilisée.

• remplacée par noexcept.
• en pratique, la liste d’autorisation est plus une entrave qu’une aide à la
gestion des exceptions,

• le test dynamique est un coût supplémentaire à la gestion d’exception,
• en terme d’optimisation du compilateur, seul compte s’il peut y avoir une
exception, et non quel est le type de l’exception lancée (donc, n’optimise

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

spécificateur noexcept
Préalable :

• Par défaut, toute fonction ou méthode est susceptible de lancer une
exception,

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Exception dynamique

noexcept

• à l’exception du destructeur qui n’ont pas le droit d’en lancer sans
provoquer la terminaison du programme.
Le spécificateur noexcept permet de changer ce comportement :

• noexcept(true) ou noexcept indique que la fonction ne génère pas
d’exception

• noexcept(false) indique que la fonction peut lancer des exceptions.

Spécificateur
Opérateur
Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
30/ 58

Exemple :
void
void
void
void

fun1 ( ) ;
fun2 ( ) noexcept ( f a l s e ) ;
fun3 ( ) noexcept ( t r u e ) ;
fun4 ( ) noexcept ;

//
//
//
//

peut l a n c e r une e x c e p t i o n
peut l a n c e r une e x c e p t i o n
ne l a n c e pas d ’ e x c e p t i o n
ne l a n c e pas d ’ e x c e p t i o n

Quel est la conséquence de ce spécificateur ?
une fonction marquée nonexcept qui génère une exception provoque une
terminaison immédiate du programme avec std::terminate().
Exemple : void die_scum_die ( ) no_except { throw 0 ; }

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Exception dynamique

noexcept
Spécificateur
Opérateur
Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
31/ 58

spécificateur noexcept
Dans le cas des templates, noexcept peut être utilisé pour disposer un
noexcept conditionnel.
Exemple :
# include < t y p e _ t r a i t s >
# include < u t i l i t y >
/ / ne l a n c e pas d ’ e x c e p t i o n s i s i z e o f ( T ) <= 4
templace <class T> void f u n c ( T ) noexcept ( s i z e o f ( T) <= 4 ) ;
/ / échange de deux v a l e u r s
template <class T> void exchange ( T& a , T& b )
noexcept (
s t d : : i s _ n o t h r o w _ m o v e _ c o n s t r u c t i b l e <T > : : v a l u e &&
s t d : : is_nothrow_move_assignable <T > : : v a l u e
) {
T tmp ( s t d : : move ( a ) ) ; / / move c o n s t r u c t i o n
a = s t d : : move ( b ) ;
/ / move assignment
b = s t d : : move ( tmp ) ;
/ / move assignment
}

La fonction exchange est marquée noexcept si la construction et
l’assignation par déplacement pour le type T sont marqués eux-aussi
comme noexcept.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Exception dynamique

noexcept
Spécificateur
Opérateur

spécificateur noexcept
Attention de bien comprendre toutes les implications de noexcept :
Un appel de fonction peut lancer des exceptions comme résultat du passage
de paramètres, de l’exécution de la fonction, et du retour de l’argument de
fonction.
C’est-à-dire :






au passage de paramètre : construction de chaque paramètre,
lors de l’exécution de la fonction,
lors de la destruction des variables locales et des paramètres,
dans le cas d’un retour par valeur, la construction de l’objet temporaire
destinée à contenir la valeur dans le contexte de la fonction appelante
(s’il n’y a pas d’élision) .

Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
32/ 58

Pour éviter une levée d’exception lors de passage de paramètres :

• passer les arguments par référence,
• faire en sorte que les constructeurs par copie/déplacement soient
noexcept.
Pour éviter une levée d’exception lors d’un retour par valeur, faire en sorte
que les constructeurs par copie/déplacement soient noexcept.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception

)
Opérateur noexcept (C++
11
Le rôle de l’opérateur noexcept permet de vérifier à la compilation que
l’expression passée à l’opérateur ne génère pas d’exception.
Exemple :
void may_throw ( ) ;
void no_throw ( ) noexcept ;

/ / noexcept ( may_throw ( ) ) = f a l s e
/ / noexcept ( no_throw ( ) ) = t r u e

Plus précisément,

• l’expression passée entre parenthèse n’est pas évaluée,
• il est vérifié que toutes les fonctions nécessaires à l’évaluation de
l’expression sont toutes noexcept (= déclarée avec le spécificateur).

Exception dynamique

noexcept
Spécificateur
Opérateur
Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
33/ 58

Cet opérateur est généralement utilisé de la manière suivante :

• dans un code actif, permet de vérifier qu’une branche de l’exécution est
bien complètement en noexcept.

• avec static_assert, permet de faire en sorte que des fonctions ne
compilent que si des spécifications noexcept sont bien vérifiées.

• dans les templates, afin de vérifier que des spécifications noexcept sont
bien vérifiées.
Exemple : template < class T> T add ( const T& x , const T& y )
noexcept ( noexcept ( x + y ) &&
s t d : : i s _ n o t h r o w _ m o v e _ c o n s t r u c t i b l e <T > : : v a l u e )
{ return x + y ; }

INFO0402 :
Méthodes de
programmation
orientée objet

Usages de noexcept

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Exception dynamique

noexcept
Spécificateur
Opérateur
Usages de noexcept

Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
34/ 58

Éviter d’utiliser ce spécificateur à moins qu’il soit clair qu’aucun
usage raisonnable (courant ou futur) de la fonction ne peut
générer d’exception,
Toutes les fonctions de calcul intensif devraient être marquée
nonexcept afin de n’avoir la gestion des exceptions que sur les
fonctions haut-niveaux :
• Les conditions d’erreur sur les fonctions bas-niveau relèvent

plus de de l’assert (code actif seulement en mode debug).
• L’utilisation d’une exception exige un code actif (les tests de

condition d’erreur) y compris après la phase de debug.
• Autant que possible, essayer de faire en sorte que les

conditions d’erreur soient évacuées de la partie la plus
active du code.

INFO0402 :
Méthodes de
programmation
orientée objet

Cadre approprié d’utilisation des exceptions

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL

Remarque : le standard ne précise pas comme les exceptions doivent être
implémentée, mais seulement le comportement qu’elles doivent respecter.
⇒ dépend l’implémentation dans le compilateur
Potentiellement, la gestion interne des exceptions :

• utilise une quantité de mémoire significative pour stocker les exceptions,
et les informations nécessaires au stack unwinding,

Spécification
d’exception

• si aucune exception est levée, ne génère quasiment pas de surcoût en

Cadre
d’utilisation

• si une exception est levée, le surcoût peut être significatif.

temps d’exécution

Introduction
Cadre d’utilisation
Exceptions contre
assertions

Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
35/ 58

En moyenne, si les exceptions sont utilisées, les codes sont :

• plus gros (5 à 10%),
• sur un compilateur moderne, aussi rapide si aucune exception n’est
lancée (5 à 10% plus lent sinon).
Ceci dépend évidemment de compilateur, et de l’implémentation utilisée.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Introduction
Cadre d’utilisation
Exceptions contre
assertions

Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
36/ 58

Cadre approprié d’utilisation des exceptions
Conséquences pratiques : l’utilisation des exceptions
• n’est pas appropriée en toutes circonstances,
• est déconseillée dans toutes les applications ou la mémoire

est limitée (systèmes embarqués),
• est déconseillée dans toutes les applications ou les

performances sont critiques (système temps-réel, rendu 3D,
...), à savoir pour lesquels les opérations doivent se terminer
dans un temps spécifique maximum déterminé,
car la longueur du chemin qui est pris pour gérer l’exception
peut être difficile à majorer
• ne doit être effectuée que dans des situations qui ne se
produisent pas fréquemment (ne pas les utiliser pour
retourner des erreurs anodines ou des warnings),
• ne doit être effectuée qu’avec des codes "exception safe" (la
plupart des codes ne le sont pas)

INFO0402 :
Méthodes de
programmation
orientée objet

Exceptions contre assertions

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Introduction
Cadre d’utilisation
Exceptions contre
assertions

Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé
37/ 58

On a vu que les assertions étaient une autre manière de vérifier que le cadre
d’exécution d’une méthode était approprié.
Savoir si les invariants doivent être assurés par les exceptions ou les
assertions est controversé,
Règle : n’utiliser les exceptions que pour les erreurs pour lesquels une
récupération est possible,
Si la condition d’erreur détectée indique une sérieuse erreur de programmation
(corruption du heap ou stack), l’état du programme ne permet de toute façon
pas de continuer l’exécution, et l’utilisation d’une exception n’est alors pas
envisageable.
Attention : tendance forte pour les programmeurs débutants à utiliser les
exceptions à de nombreux endroits où elles sont très discutables ou clairement
inappropriés.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Garantie "exception
safe"
Idiome RAII

Implémentation
interne
Exceptions
avancées
Résumé

Problème d’utilisation : introduction
La levée d’exception pose potentiellement des problèmes importants de fuite
mémoire, et plus généralement les fuite de ressources.
1 Que se passe-t-il dans le code suivant si useBuffer() lance une

exception ?
void u s e B u f f e r ( char * b u f ) { . . . }
void doWork ( ) {
char * b u f = new char [ 1 0 2 4 ] ;
useBuffer ( buf ) ;
delete [ ] buf ;
}

Réponse : le code qui libère buf n’est jamais atteint.
2 Pour la structure du code suivant, est-elle fondamentalement

dangeureuse (sous l’hypothèse qu’aucune fonction ci-dessus ne gère les
exceptions, et que celle-ci est reléguée dans les fonctions appelantes) ?
void f u n c ( ) {
initialize ();
do_work ( ) ;
cleanup ( ) ;
}

Ce code n’est pas "exception safe" : si do_work() lance une exception,

cleanup() n’est jamais effectué.
38/ 58

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Garantie "exception
safe"
Idiome RAII

Implémentation
interne
Exceptions
avancées
Résumé

Problème d’utilisation des exceptions : exemples
Exemple 1 :
T& T : : operator =(T const& x ) {
i f ( t h i s ! = &x ) {
t h i s −>~T ( ) ; / / d e s t r o y i n p l a c e
new ( t h i s ) T ( x ) ; / / c o n s t r u c t i n p l a c e
}
return * this ;
}

Problème : si la construction par copie échoue, alors laisse this détruit, donc
problème.
Exemple 2 :
template <class T> T Stack <T > : : pop ( ) {
i f ( t o p < 0 ) throw " pop on empty s t a c k " ;
r e t u r n v [ top − − ];
}

Problème : le retour de l’objet se fait par valeur, donc appelle le constructeur
par copie, et si ce dernier lance une exception, il n’y a aucun moyen de
récupérer la valeur.
Solution : faire un T& top() qui permet de récupérer la valeur, et void pop()
qui permet de dépiler. On sépare donc l’opération en deux étapes.

39/ 58

INFO0402 :
Méthodes de
programmation
orientée objet

Exception safe

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Garantie "exception
safe"
Idiome RAII

Implémentation
interne
Exceptions
avancées
Résumé

40/ 58

De façon à ce que le mécanisme d’exception soit utile, il est nécessaire de
savoir ce qui peut être supposé sur l’état d’un programme lorsqu’une exception
est lancée.
On dit alors qu’une opération est "exception safe" si elle laisse le programme
dans un état valide lorsque celle-ci s’est terminée en raison d’une exception.
Il existe différents garantie d’un composant vis-à-vis des exceptions :

• garantie de base : les invariants sont préservés, et aucune ressource
n’est perdue.
toutes les données stockées contiennent des valeurs valides, mais il peut
y avoir des effets de bord (valeurs modifiées par l’exception).

• garantie forte = garantie de base + pas d’effets de bord
toutes les données conservent leurs valeurs avant exception.

• garantie nothrow : garantie qu’aucune exception ne sera levée dans
toutes les situations. Si une exception est levée, elle sera traitée de
manière interne et non visible depuis l’extérieur du composant.

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Garantie "exception safe"
Règles pour la gestion d’exception :

• supposer que toutes les fonctions peuvent lever une exception, sauf si
Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Garantie "exception
safe"
Idiome RAII

l’on a la connaissance certaine du contraire.

• tout code doit au minimum fournir une garantie de base,
• la garantie nothrow doit toujours être garantie par les destructeurs, les
constructeurs et assignations par déplacement, les opérations de swap.

• ne fournir une garantie forte que lorsqu’elle est naturelle, et qu’elle n’est
pas plus coûteuse qu’une garantie de base,
Exemples dans la STL :

• garantie forte : push_back pour un conteneur STL, insert dans une
std::list

• garantie nothrow : swap entre deux conteneurs STL, pop_back pour un
conteneur STL.

Implémentation
interne

Notes : voir section exception de la documentation des méthodes.

Exceptions
avancées

Extrait de la section Exception de std::vector::push_back

Résumé

41/ 58

I f an e x c e p t i o n i s thrown , t h i s f u n c t i o n has no e f f e c t ( s t r o n g e x c e p t i o n guarantee ) .
I f T ’ s move c o n s t r u c t o r i s n o t noexcept and T i s n o t C o p y I n s e r t a b l e i n t o * t h i s ,
v e c t o r w i l l use t h e t h r o w i n g move c o n s t r u c t o r . I f i t throws , t h e guarantee i s
waived and t h e e f f e c t s are u n s p e c i f i e d . ( s i n c e C++11)

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Garantie "exception
safe"
Idiome RAII

Implémentation
interne
Exceptions
avancées
Résumé

42/ 58

Idiome RAII
RAII est l’acronyme de Resource Acquisitation Is Initialization.
L’idiome RAII est utilisé pour éviter les fuite de ressources et fournir une sureté
d’exception.
Principe :

• faire toujours en sorte que la ressource soit détenue par un objet (dit
objet RAII),

• la durée de vie de la ressource est directement liée à la vie de l’objet
RAII,

• la ressource est acquise lors de la création de l’objet RAII (i.e. dans son
constructeur),

• la ressource est libérée lors de la destruction de l’objet RAII (i.e. dans
son destructeur).
Du fonctionnement des exceptions lors du stack unwinding, il apparaît que les
objets locaux sont toujours correctement libérés.
En conséquence, tout objet RAII qui contient une ressource devra être un objet
local (au niveau du code où il est nécessaire) de façon à ce que son
destructeur soit toujours appelé (si nécessaire) lors du traitement de
l’exception.

INFO0402 :
Méthodes de
programmation
orientée objet

Idiome RAII

Pascal Mignot

Exemple :
Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Garantie "exception
safe"
Idiome RAII

Implémentation
interne
Exceptions
avancées
Résumé

43/ 58

/ / peut l a n c e r une e x c e p t i o n
void u s e B u f f e r ( char * b u f ) { . . . }
/ / s i u s e B u f f e r l a n c e une e x c e p t i o n , l a r e s s o u r c e p o i n t é e
/ / par b u f n ’ e s t j a m a i s l i b é r é e
void doWorkUnsafe ( ) {
char * b u f = new char [ 1 0 2 4 ] ;
useBuffer ( buf ) ;
delete [ ] buf ;
}
/ / idiome RAII : l a r e s s o u r c e e s t associée à une v a r i a b l e
/ / l o c a l e b u f q u i l i b è r e l a r e s s o u r c e dans son d e s t r u c t e u r
/ / ( appelé l o r s du s t a c k unwinding )
void doWorkSafe ( ) {
s t d : : u n i q u e _ p t r <char [ ] > b u f
= s t d : : make_unique<char [ ] > ( 1 0 2 4 ) ;
useBuffer ( buf ) ;
}

INFO0402 :
Méthodes de
programmation
orientée objet

Implémentation interne des exceptions

Pascal Mignot

Essentiellement, on a besoin de stocker :
Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

44/ 58

• l’objet associé à l’exception :
• en général, pas pratique de créer l’objet associé à l’exception dans
le stack, puisque l’objet a fréquemment besoin d’être propagé à
travers de nombreux niveaux de la pile d’appel,
• il est normalement petit, mais une partie peut être stockée dans le
heap si plus de mémoire est nécessaire.

• les informations nécessaires pour le stack unwinding :
• elles doivent contenir suffisamment d’information pour permettre de
libérer tous les objets temporaires, et remonter la pile d’appel
jusqu’à le handler capable de traiter l’exception,
• deux stratégies principales :
• stratégie basée sur le stack
• stratégie basée sur une table

INFO0402 :
Méthodes de
programmation
orientée objet

Implémentation interne des exceptions

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

Stratégie basée sur le stack
• Principe :
• les informations sont placées dans le stack (liste des

destructeurs à exécuter, et handlers des exceptions à
exécuter lorsqu’une exception est lancée),
• lorsqu’une exception est lancée, on parcours le stack en
exécutant les destructeurs jusqu’à ce qu’un handler soit
trouvé.
• Remarques :
• utilise du temps à l’exécution pour pousser dans le stack les
informations nécessaires à cette gestion.
• utilise de la place dans le stack (qui peut être conséquente)
en plus des informations pour exécuter le programme,

⇒ gaspillage de ressources lorsqu’aucune exception n’est
lancée.

45/ 58

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

Implémentation interne des exceptions
Stratégie basée sur une table
• Principes :
• stocke les information pour permettre le stack unwind dans

des tables statiques à l’extérieur du stack,
• la pile d’appel est utilisée pour déterminer le point

d’exécution courant à chaque niveau,
• une recherche dans les tables statiques permettent de

déterminer où l’exception lancée sera traitée, et quels sont
destructeurs à exécuter (déduit du point d’éxecution
courant).
• Remarques :
• utilise moins d’espace sur le stack (seulement la position
des try-bloc),
• requiert un stockage important pour les tables statiques,
• pas de coût supplémentaire à l’exécution

⇒ gaspillage de ressources lorsqu’aucune exception n’est
lancée.
46/ 58

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Implémentation interne des exceptions
Construction de la table statique :

• une fonction est découpée en segments de code consécutifs (chaque
Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation

segment est numéroté).
voir ci-dessous comment (blocs try + variables locales)

• données à disposer lors de gestion des exceptions :
à chaque étage de la pile des appels,
• exception handler (pointeur de fonction) sur la fonction à utiliser
pour gérer les exceptions.
• une liste de tryblocks qui contient pour chaque try :
1 le plage de segments de code qui correspond au try.
2 une liste de catchblock qui contient pour chaque catchblock :

Implémentation
interne

• le type d’exception géré par ce catchblock
• un pointeur vers le code du catchblock

Exceptions
avancées

généré par le compilateur.

Résumé

47/ 58

• une liste de nettoyage qui contient la liste des variables locales à
libérer ainsi que le pointeur vers la fonction de libération
(destructeur). ordonnée, générée par le compilateur

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Implémentation interne des exceptions
Utilisation de la table statique lors de la génération d’une exception :
1 à partir du numéro du segment, recherche dans la liste des tryblocks à

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

quel tryblock appartient l’instruction qui a généré l’exception.
2 si il existe un tel tryblock alors

(a) recherche d’un catch permettant de gérer cette exception (RTTI)
dans la liste des catchblocks.
(b) s’il en existe un, alors aller en 4.
3 si on est au sommet de la pile

alors sortie du programme sur erreur (exception non gérée)
sinon remonter à l’appellant dans la pile des appels, et aller en 1.
4 dépiler la pile des appels pour se trouver sur le "frame block" contenant

le catch.
utiliser la liste de nettoyage de chaque "frame block" pour libérer la
mémoire locale allouée au point courant de l’exécution.
5 exécuter le catchblock trouvé en 2.b.
6 poursuivre le code qui suit le catchblock.

48/ 58

INFO0402 :
Méthodes de
programmation
orientée objet
Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
Résumé

49/ 58

Implémentation interne des exceptions
La gestion d’une exception dans une méthode ajoute donc :

• un prologue (support des exceptions).
• un épilogue (code à exécuter en cas d’exception).
pour toutes les fonctions (y compris celle qui n’ont pas de try/catch).
noexcept indique que la fonction ne doit pas contenir cet ajout.
En terme de performance :

• L’exécution du prologue est court :
ajout essentiellement de pointeurs de fonction et de pointeurs vers des
structures précompilées.

• L’exécution de l’épilogue (gestion d’une exception lancée) peut
prendre du temps :
• identification du try et du catch avec recherche éventuelle

dans la pile, nettoyage des variables locales allouées
jusqu’au point d’exception.
• d’autant plus que l’exception n’est pas gérée dans la
fonction qui l’engendre.
ajouter le coût du constructeur/destructeur de l’objet de
gestion de l’exception (si géré avec un objet).

INFO0402 :
Méthodes de
programmation
orientée objet

Outils avancés pour les exceptions

Pascal Mignot

Introduction
Gestion
classique
Bases
Exception STL
Spécification
d’exception
Cadre
d’utilisation
Problème
d’utilisation
Implémentation
interne
Exceptions
avancées
stack unwinding
Stockage et
récupération
Exceptions
imbriquées

Terminate

Résumé
50/ 58

Dans cette partie, nous abordons des outils avancés pour la
gestion d’exception, à savoir :
• Comment détecter que la portion de code actuellement

exécutée s’effectue lors d’un "stack unwinding" ?
• Comment stocker, récupérer et transférer une exception ?
• Comment gérer l’imbrication exception ?
• Comment gérer la terminaison d’un code ?


Aperçu du document 08-Gestion_des_exceptions.pdf - page 1/58

 
08-Gestion_des_exceptions.pdf - page 3/58
08-Gestion_des_exceptions.pdf - page 4/58
08-Gestion_des_exceptions.pdf - page 5/58
08-Gestion_des_exceptions.pdf - page 6/58
 




Télécharger le fichier (PDF)


Télécharger
Formats alternatifs: ZIP Texte



Documents similaires


08 gestion des exceptions
chapitre4
tpcs5
partiel 2011 1
cours poo amira final
cours cppc

Sur le même sujet..




🚀  Page générée en 0.012s