Vous êtes sur la page 1sur 39

C++ : exception

Achref El Mouelhi

Docteur de l’université d’Aix-Marseille


Chercheur en programmation par contrainte (IA)
Ingénieur en génie logiciel

elmouelhi.achref@gmail.com

H & H: Research and Training 1 / 28


Introduction

C++

Exception ?
H I ©
C’est une erreur qui se produit pendant l’ex
U L de notre
Eécution
programme
L MO
Une exception dans e
r E
unfprogramme implique généralement son
c h
©A
arrêt d’exécution

H & H: Research and Training 2 / 28


Introduction

C++

Comment faire pour poursuivre l’exécution ?

H I ©
EL
Repérer les blocs pouvant lancer une exception
U
O
LM
Capturer l’exception correspondante

r e f E
Afficher un message relatif à cette exception
ch
©A
Continuer l’exécution

H & H: Research and Training 3 / 28


Introduction

Étant donnée la fonction suivante qui calcule la division de deux entiers

int division (int x, int y)


{
return x / y;
}

H I ©
U EL
O
f E LM
ch r e
©A

H & H: Research and Training 4 / 28


Introduction

Étant donnée la fonction suivante qui calcule la division de deux entiers

int division (int x, int y)


{
return x / y;
}

Appelons cette fonction dans le main


H I ©
int main()
U EL
{
O
int i = 3, j = 0;
cout << division(i, j) << endl;
f E LM
r e
cout << "Message à afficher si l'exception est capturée";
return 0;
ch
}
©A

H & H: Research and Training 4 / 28


Introduction

Étant donnée la fonction suivante qui calcule la division de deux entiers

int division (int x, int y)


{
return x / y;
}

Appelons cette fonction dans le main


H I ©
int main()
U EL
{
O
int i = 3, j = 0;
cout << division(i, j) << endl;
f E LM
r e
cout << "Message à afficher si l'exception est capturée";
return 0;
ch
}
©A
À l’exécution

rien n’est affiché mais le programme ne retourne pas de zéro

H & H: Research and Training 4 / 28


Lancement et capture d’exception

C++

Comment faire pour gérer une exception ?

Identifier les instructions susceptible d’arrêter l’exécution d’un


programme
H I ©
U ELexception
Utiliser l’instruction throw pour lancer une
Utiliser un bloc try { ... L MO { ... }
} catch
r e f E
Le try { ...c}h pour entourer une instruction qui pourrait
A
© exception
lancer une
Le catch { ... } pour capturer l’exception et afficher un
message qui lui correspond

H & H: Research and Training 5 / 28


Lancement et capture d’exception

C++
Commençons par modifier la fonction division pour lancer une exception si y = 0

int division(int x, int y)


{
if (y == 0)
{

}
throw string("division / 0");

H I ©
return x / y;
UEL
}
O
f E LM
ch r e
©A

H & H: Research and Training 6 / 28


Lancement et capture d’exception

C++
Commençons par modifier la fonction division pour lancer une exception si y = 0

int division(int x, int y)


{
if (y == 0)
{

}
throw string("division / 0");

H I ©
return x / y;
UEL
}
O
f E LM
ch r e
Explication
©A
Si y = 0, on arrête l’exécution de cette fonction

La fonction ne retournera pas d’entier

Mais elle lance une exception et envoie un message de type string dont le contenu est
division / 0

H & H: Research and Training 6 / 28


Lancement et capture d’exception

Ajoutons les deux blocs try et catch dans l’appel de la fonction dans le main

int main()
{
int i = 3, j = 0;
try
{
cout << division(i, j) << endl;
}
catch (string const &msg)
{

}
cout << "Erreur : " << msg << endl;

H I ©
EL
cout << "Message à afficher si l'exception est capturée";

U
return 0;
}
O
f E LM
ch r e
©A

H & H: Research and Training 7 / 28


Lancement et capture d’exception

Ajoutons les deux blocs try et catch dans l’appel de la fonction dans le main

int main()
{
int i = 3, j = 0;
try
{
cout << division(i, j) << endl;
}
catch (string const &msg)
{

}
cout << "Erreur : " << msg << endl;

H I ©
EL
cout << "Message à afficher si l'exception est capturée";

U
return 0;
}
O
f E LM
En exécutant
ch r e
Erreur : division / 0
©A
Message à afficher si l’exception est capturée

H & H: Research and Training 7 / 28


Lancement et capture d’exception

Ajoutons les deux blocs try et catch dans l’appel de la fonction dans le main

int main()
{
int i = 3, j = 0;
try
{
cout << division(i, j) << endl;
}
catch (string const &msg)
{

}
cout << "Erreur : " << msg << endl;

H I ©
EL
cout << "Message à afficher si l'exception est capturée";

U
return 0;
}
O
f E LM
En exécutant
ch r e
Erreur : division / 0
©A
Message à afficher si l’exception est capturée

Explication

msg contient la chaı̂ne envoyée par l’instruction throw

H & H: Research and Training 7 / 28


Exceptions personnalisées

C++

Remarque

H I ©
EL
Pour l’exemple précédent, on a géré les exceptions en
transmettant des chaı̂nes de caractère
M OU
Il serait plus pertinent de E
f L une classe exception et lui
définir
envoyer les param e
r pour qu’elle construise le message
chètres
© A
d’erreur adéquat

H & H: Research and Training 8 / 28


Exceptions personnalisées

Définissons la classe d’exception suivante (ArithmeticException.h)

#ifndef ARITHMETICEXCEPTION_H
#define ARITHMETICEXCEPTION_H

#include <string>

using namespace std;

H I ©
EL
class ArithmeticException
{
public:
O U
second){};
f E LM
ArithmeticException(int first, int second) : first(first), second(

ch r e
string getMessage() { return "Problème de division : " + to_string(

©A
first) + " / " + to_string(second); };

private:
int first;
int second;
};

#endif

H & H: Research and Training 9 / 28


Exceptions personnalisées

C++
Modifions maintenant la fonction division()

int division (int x, int y)


{
if (y == 0)
{
H I ©
EL
throw ArithmeticException(x, y);
}
O U
LM
return x / y;
}

r e f E
ch
©A

H & H: Research and Training 10 / 28


Exceptions personnalisées

C++
Modifions maintenant la fonction division()

int division (int x, int y)


{
if (y == 0)
{
H I ©
EL
throw ArithmeticException(x, y);
}
O U
LM
return x / y;
}

r e f E
ch
©A
Remarque (pour les développeurs Java, C#...)

Si on fait throw new ArithmeticException(x, y), alors il ne faut pas oublier


de libérer la mémoire avec delete

H & H: Research and Training 10 / 28


Exceptions personnalisées

Pour tester

int main()
{
int i = 3, j = 0;
try
{
cout << division(i, j) << endl;
}
catch (ArithmeticException &e)
H I ©
{
UEL
cout << e.getMessage() << endl;
O
}

f E LM
cout << "Message à afficher si l'exception est capturée";

}
return 0;
ch r e
©A

H & H: Research and Training 11 / 28


Exceptions personnalisées

Pour tester

int main()
{
int i = 3, j = 0;
try
{
cout << division(i, j) << endl;
}
catch (ArithmeticException &e)
H I ©
{
UEL
cout << e.getMessage() << endl;
O
}

f E LM
cout << "Message à afficher si l'exception est capturée";

}
return 0;
ch r e
©A
Le résultat est

Problème de division : 3 / 0
Message à afficher si l’exception est capturée

H & H: Research and Training 11 / 28


Hiérarchie d’exceptions

C++

H I ©
EL
On peut définir une deuxième condition

O U
LM
Les deux entiers à utiliser dans la fonction division ne doivent pas

r e f E
dépasser une borne max (par exemple 5) sinon on lève une exception.

ch
©A

H & H: Research and Training 12 / 28


Hiérarchie d’exceptions

Définissons la nouvelle exception UpperBoundException

#ifndef UPPERBOUNDEXCEPTION_H
#define UPPERBOUNDEXCEPTION_H

#include <string>

using namespace std;

class UpperBoundException
H I ©
{
UEL
public:
O
LM
UpperBoundException(int param) : param(param) {}
string getMessage()
{
r e f E
ch
return "Valeur max autorisée (5) dépassée, valeur saisie : " +

} ©A
to_string(param);

private:
int param;
};

#endif

H & H: Research and Training 13 / 28


Hiérarchie d’exceptions

C++
Modifions la fonction division()

int division (int x, int y)


{
if (x > 5)
{
H I ©
EL
throw UpperBoundException(x);
}
O U
LM
if (y > 5)
{

r e
throw UpperBoundException(y);f E
}
ch
if (y == 0)
{ ©A
throw ArithmeticException(x, y);
}
return x / y;
}

H & H: Research and Training 14 / 28


Hiérarchie d’exceptions

Testons toutes ces exceptions dans le main()

int main()
{
int i = 6, j = 0;
try
{
cout << division(i, j) << endl;
H I ©
EL
}
catch (UpperBoundException & e)
O U
LM
{

}
cout << e.getMessage() << endl;
r e f E
ch
©A
catch (ArithmeticException & e)
{
cout << e.getMessage() << endl;
}
cout << "Message à afficher si l'exception est capturée";
return 0;
}

H & H: Research and Training 15 / 28


Hiérarchie d’exceptions

C++

Remarques

On peut définir plusieurs blocs catch

H I ©
EL
On peut à la fin par exemple ajouter une exception plus générale
U
O
catch (exception & e) pour capturer les exceptions
standards
f E LM
ch r e
Pour capturer le reste, on peut aussi ajouter en dernier catch (
... )
©A
Il faut toujours partir du plus spécifique et aller vers le plus général

H & H: Research and Training 16 / 28


Fusion de catch

C++

H I ©
EL
Question : comment fusionner tous ces blocs de catch en un seul ?

O U
Créer une classe mère abstraite BaseException pour toutes les
classes d’exception précédentes
f E LM
ch r e
©A

H & H: Research and Training 17 / 28


Fusion de catch

C++
Code de BaseException
#ifndef BASEEXCEPTION_H
#define BASEEXCEPTION_H

#include <string>
H I ©
UEL
using namespace std; O
f E LM
class BaseException
ch r e
{
public: ©A
virtual string getMessage() = 0;
};

#endif

H & H: Research and Training 18 / 28


Fusion de catch

C++

Mettons à jour ArithmeticException

#ifndef ARITHMETICEXCEPTION_H
#define ARITHMETICEXCEPTION_H

#include <string>
#include "BaseException.h"

H I ©
EL
using namespace std;

class ArithmeticException : public BaseException


O U
LM
{
public:

string getMessage()
r e E
ArithmeticException(int first, int second) : first(first), second(second){};
f
ch
{

©A
return "Problème de division : " + to_string(first) + " / " + to_string(second);
};

private:
int first;
int second;
};

#endif

H & H: Research and Training 19 / 28


Fusion de catch

C++

Et UpperBoundException

#ifndef UPPERBOUNDEXCEPTION_H
#define UPPERBOUNDEXCEPTION_H

#include <string>
#include "BaseException.h"

H I ©
EL
using namespace std;

class UpperBoundException : public BaseException


O U
LM
{
public:

string getMessage()
r e f E
UpperBoundException(int param) : param(param) {}

{
ch
©A
return "Valeur max autorisée (5) dépassée, valeur saisie : " + to_string(param);
}

private:
int param;
};

#endif

H & H: Research and Training 20 / 28


Fusion de catch

C++

Le nouveau main()

int main()
{
int i = 6, j = 0;
try
H I ©
{
UEL
cout << division(i, j) << endl;
O
}
f E LM
catch (BaseException &e)
{
ch r e
} ©A
cout << e.getMessage() << endl;

cout << "Message à afficher si l'exception est capturée";


return 0;
}

H & H: Research and Training 21 / 28


Exceptions standards

C++

Exceptions standards
H I ©
EL
Plusieurs exceptions prédéfinies dans le namespace std
U
O
LM
Pour les capturer, on peut utiliser la classe prédéfinie exception

r e f E
La méthode what() de cette classe retourne le motif de
ch
©A
l’exception

H & H: Research and Training 22 / 28


Exceptions standards

C++
Exemple d’échec de conversion de string en int

int main()
{
string str = "bonjour";
try
{

}
int i = stoi(str);

H I ©
EL
catch (exception & e)
{
cout << "Erreur : " << e.what() << endl;
O U
LM
}
cout << "Message à afficher si l'exception est capturée";

}
return 0;

r e f E
ch
©A

H & H: Research and Training 23 / 28


Exceptions standards

C++
Exemple d’échec de conversion de string en int

int main()
{
string str = "bonjour";
try
{

}
int i = stoi(str);

H I ©
EL
catch (exception & e)
{
cout << "Erreur : " << e.what() << endl;
O U
LM
}
cout << "Message à afficher si l'exception est capturée";

}
return 0;

r e f E
ch
©A
En exécutant

Erreur : stoi
Message à afficher si l’exception est capturée

H & H: Research and Training 23 / 28


Exceptions standards

C++
Exemple de problème de création de vecteur

int main()
{
try
{
vector<int> vecteur (500000000);
}
catch (exception & e)
H I ©
{
cout << "Erreur : " << e.what() << endl;
UEL
}
O
LM
cout << "Message à afficher si l'exception est capturée";

E
return 0;
}

r e f
ch
©A

H & H: Research and Training 24 / 28


Exceptions standards

C++
Exemple de problème de création de vecteur

int main()
{
try
{
vector<int> vecteur (500000000);
}
catch (exception & e)
H I ©
{
cout << "Erreur : " << e.what() << endl;
UEL
}
O
LM
cout << "Message à afficher si l'exception est capturée";

E
return 0;
}

r e f
ch
©A
En exécutant

Erreur : std : :bad alloc


Message à afficher si l’exception est capturée

H & H: Research and Training 24 / 28


Assertions

C++

Exceptions

Les exceptions sont utilisées pour les erreurs d’exécution (erreurs


d’entrée/sortie, mémoire insuffisante, problème de connexion à la base de
données...)
H I ©
U
Elles doivent être utilisées pour vérifier les problèmes L pourraient arriver.
Equi
L MO
r e f E
A ch
©

H & H: Research and Training 25 / 28


Assertions

C++

Exceptions

Les exceptions sont utilisées pour les erreurs d’exécution (erreurs


d’entrée/sortie, mémoire insuffisante, problème de connexion à la base de
données...)
H I ©
U
Elles doivent être utilisées pour vérifier les problèmes L pourraient arriver.
Equi
L MO
r e f E
A ch
©
Assertions, pourquoi ?

Pour vérifier des choses qui ne devraient jamais arriver, on utilise les assertions.

Elles peuvent être considérées comme un moyen de débogage.

H & H: Research and Training 25 / 28


Assertions

C++

Assertions ?
Permettent de vérifier si une condition est vraie

H I ©
Si oui, le programme continue.
UEL
O
LM
Sinon, le programme s’arrête et indique la source d’erreur.

r e f E
ch
©A

H & H: Research and Training 26 / 28


Assertions

C++

Assertions ?
Permettent de vérifier si une condition est vraie

H I ©
Si oui, le programme continue.
UEL
O
LM
Sinon, le programme s’arrête et indique la source d’erreur.

r e f E
ch
©A
Pour utiliser les assertions, on ajoute
#include <cassert>

H & H: Research and Training 26 / 28


Assertions

C++
Considérons le code suivant

int main()
{
int i;
cout << "saisissez un entier positif " << endl;
H I ©
EL
// saisissez une valeur négative
cin >> i;
O U
LM
if (i % 3 == 0)
{

r e f E
cout << i << " est divisible par 3" << endl;
}
ch
else
{ ©A
assert(i % 3 == 1 || i % 3 == 2);
cout << i << " n'est pas divisible par 3" << endl;
}
}

H & H: Research and Training 27 / 28


Assertions

C++

H I ©
EL
Remarque

O U
Dans le cas où l’utilisateur saisit une valeur négative, nous nous
E LM
rendrons compte que ce cas n’est pas compris dans le else.
f
ch r e
©A

H & H: Research and Training 28 / 28

Vous aimerez peut-être aussi