1242.2 Langage C++ - 2025-2026
1. Gestion des erreurs
2. Principe des exceptions
3.
4. Relance d'exceptions
5.
6.
// f(x) = x^2, for x > 0
// Else, returns an error code
#define ERROR_CODE -1
int f(int x)
{
if (x <= 0)
return ERROR_CODE;
return x*x;
}
int main()
{
int x = 0;
int result = ERROR_CODE;
std::cin >> x;
result = f(x);
if (result == ERROR_CODE)
std::println("Error");
else
std::println(result);
return 0;
}
Code de gestion d'erreurs mélangé au "vrai" code
L'appelant doit savoir ce que signifient les codes d'erreurs retournés
Retourner une valeur et un code d'erreur en même temps
// f(x) = x^2, for x > 0
// Else, throws an exception
#define ERROR_CODE -1
int f(int x)
{
if (x <= 0)
throw ERROR_CODE;
return x*x;
}
int main()
{
int x = 0;
int result = -1;
std::cin >> x;
try
{
result = f(x);
}
catch (...)
{
std::println("Error caught");
}
std::println("result: {}", result);
}
Lors de la détection d'une «erreur» (fonctionnement imprévu)
Lorsqu'une exception est lancée (avec
L'exception remonte les fonctions appelantes jusqu'à être attrapée (avec
Si elle n'est pas attrapée, alors le programme se termine
Les exceptions permettent de séparer le traitement d'erreur du reste du code
Les instructions pouvant lever une exception doivent être à l'intérieur d'un bloc :
Un bloc
Une exception est levée par l'instruction :
int main()
{
auto diviseur = 0;
try
{
if (diviseur == 0) throw diviseur;
std::println("Q: {}", dividende/diviseur);
}
catch (int &d) // Exception handler for int
{
std::println("Division par {}", d);
}
catch (...) // Exception handler for all other types
{
std::println("Another error");
}
return 0;
}
Le premier gestionnaire compatible avec le type de l'exception l'attrape
Au plus un gestionnaire est exécuté pour une exception levée
Donc, si plusieurs gestionnaires sont appropriés pour le type de l'exception, seul le premier sera exécuté
Il convient donc de commencer par les gestionnaires les plus spécialisés, et terminer par le plus général
Pour être gérable, une exception doit être levée dans un bloc
try
{
throw "err!";
}
void foo()
{
throw ERROR_CODE_27;
}
try
{
foo();
}
Si l'instruction
Un bloc
try {
// Instructions
}
catch (int except1) { // Handle int exceptions
// Instructions
}
catch (std::string except2) { // Handle string exceptions
// Instructions
}
catch (std::exception &except3) { // Handle std::exception exceptions
// Instructions
}
catch (...) { // Handle all other exceptions
// Instructions
}
// NOTE: no need for breaks here
try {
switch(i) {
case 1: throw 2;
case 2: throw "Error!";
case 3: throw objet;
}
}
catch(int x) {
std::println("Integer exception: {}", x);
}
catch(const char* str) {
std::println("String exception: {}", str);
}
catch(Classe &obj) {
std::println("Object exception: {}", obj.print());
}
Lorsqu'une exception de type
1. de type
2. de superclasse de
3. pointeur sur une classe dérivée
4. type indéterminé :
Si l'exception est levée dans une fonction, le compilateur cherche un gestionnaire dans la fonction. Si ce n'est pas le cas, dans la fonction appelante, etc.
Le gestionnaire peut mettre fin au programme. Si ce n'est pas le cas, l'exécution continue par l'instruction qui suit les gestionnaires :
Si aucun gestionnaire n'est trouvé, il appelle la fonction
Le principal problème lié aux exceptions est la libération des ressources :
- Libérer les ressources allouées dynamiquement
- Fermer les flux
1. Les allocateurs
2. RAII (Resource Acquisition Is Initialization)
Il est possible de relancer une exception déjà lancée
Il faut utiliser l'instruction
void foo()
{
try {
int n=2;
throw n;
}
catch(int) {
std::println("Caught in foo");
throw;
}
}
int main()
{
try {
foo();
}
catch(int) {
std::println("Caught in main");
// Now end the program
}
return 0;
}
Le mot clé
Il est possible de spécifier une condition pour lever une exception
// Do not throw an exception
void f1() noexcept(true) { ... }
// Might throw an exception
void f2() noexcept(false) { ... }
// Might throw an exception if expr is false
void f3() noexcept(expr) { ... }
// Might throw an exception if foo() may throw too
void f4() noexcept(noexcept(foo())) { ... }
La bibliothèque standard définit des classes exceptions
Leur superclasse commune est
Elle est définie dans le fichier d'en-tête
Elle comporte une méthode
Les exceptions personnalisées hériteront donc de
Double intérêt :
1. Transmettre des informations (attributs, what())
2. catch (const exception &e) plutôt que catch(...)
#include <print>
#include <stdexcept> // or #include <exception>
class Exception1 : public std::exception {
public:
Exception1() noexcept {}
const char* what() const noexcept override {
return "exception1";
}
};
class Exception2 : public std::exception {
public:
Exception2() noexcept {}
const char* what() const noexcept override {
return "exception2";
}
};
int main()
{
try {
std::println("block try 1");
throw Exception1();
}
catch(const Exception1 &e) {
std::println("Caught Exception1: {}", e.what());
}
try {
std::println("block try 2");
throw Exception2();
}
catch (const std::exception &e) {
std::println("Caught exception: {}", e.what());
}
return 0;
}