Introduction
Dans ce laboratoire (lab), vous allez apprendre les concepts fondamentaux de la gestion des exceptions en C++. Vous commencerez par comprendre comment lancer (throw) et capturer (catch) des exceptions de base, qui sont un moyen de gérer les erreurs d'exécution ou les situations inattendues dans votre programme. Vous explorerez ensuite l'utilisation des mots-clés try, catch et throw, ainsi que des classes d'exceptions standard telles que std::exception. De plus, vous apprendrez à définir des classes d'exceptions personnalisées et à implémenter plusieurs blocs catch pour différents types d'exceptions. Enfin, vous explorerez l'utilisation de blocs try-catch imbriqués pour gérer les exceptions à différents niveaux de votre programme.
Lancer et capturer des exceptions de base
Dans cette étape, vous allez apprendre les concepts fondamentaux de la gestion des exceptions en C++, en vous concentrant sur la manière de lancer (throw) et de capturer (catch) des exceptions de base. Les exceptions sont un moyen de gérer les erreurs d'exécution ou les situations inattendues dans votre programme.
Ouvrez le WebIDE et créez un nouveau fichier appelé basic_exceptions.cpp dans le répertoire ~/project :
touch ~/project/basic_exceptions.cpp
Ajoutez le code suivant à basic_exceptions.cpp :
#include <iostream>
#include <stdexcept>
int divide(int numerator, int denominator) {
// Throw an exception if denominator is zero
if (denominator == 0) {
throw std::runtime_error("Division by zero is not allowed!");
}
return numerator / denominator;
}
int main() {
try {
// Attempt a normal division
int result1 = divide(10, 2);
std::cout << "10 / 2 = " << result1 << std::endl;
// Attempt division by zero
int result2 = divide(10, 0);
std::cout << "This line will not be executed" << std::endl;
}
catch (const std::exception& e) {
// Catch and handle the exception
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}
Décortiquons les éléments clés :
Mot-clé
throw:- Utilisé pour générer une exception lorsqu'une erreur se produit
- Dans cet exemple, nous lançons une
std::runtime_errorlorsque l'on tente de diviser par zéro
Bloc
try:- Contient le code qui peut générer une exception
- Vous permet d'effectuer des opérations risquées
- Si une exception se produit, le contrôle du programme passe au bloc
catch
Bloc
catch:- Gère l'exception lancée dans le bloc
try - Capture les exceptions d'un type spécifique (ici,
std::exception) - Utilise
e.what()pour obtenir le message d'erreur
- Gère l'exception lancée dans le bloc
Compilez et exécutez le programme :
g++ basic_exceptions.cpp -o basic_exceptions
./basic_exceptions
Exemple de sortie :
10 / 2 = 5
Error: Division by zero is not allowed!
Points clés concernant la gestion des exceptions de base :
- Les exceptions offrent un moyen de gérer les erreurs d'exécution de manière élégante
throwgénère une exceptiontryetcatchfonctionnent ensemble pour gérer les situations exceptionnelles- Empêche les plantages du programme en fournissant une gestion contrôlée des erreurs
Comprendre les mots-clés try, catch et throw
Dans cette étape, vous allez approfondir vos connaissances sur les trois mots-clés clés de la gestion des exceptions en C++ : try, catch et throw. Ces mots-clés fonctionnent ensemble pour créer un mécanisme de gestion des erreurs robuste dans vos programmes.
Ouvrez le WebIDE et créez un nouveau fichier appelé exception_keywords.cpp dans le répertoire ~/project :
touch ~/project/exception_keywords.cpp
Ajoutez le code suivant à exception_keywords.cpp :
#include <iostream>
#include <string>
// Function that might throw an exception
int processAge(int age) {
// Throw an exception for invalid age
if (age < 0) {
throw std::string("Age cannot be negative");
}
if (age > 120) {
throw std::string("Age is unrealistically high");
}
return age;
}
int main() {
// First try block: handling age validation
try {
// Successful case
int validAge = processAge(25);
std::cout << "Valid age: " << validAge << std::endl;
// This will throw an exception
int invalidAge1 = processAge(-5);
std::cout << "This line will not be executed" << std::endl;
}
catch (const std::string& errorMessage) {
// Catch block to handle the thrown exception
std::cout << "Error: " << errorMessage << std::endl;
}
// Second try block: another example
try {
// This will throw another exception
int invalidAge2 = processAge(150);
std::cout << "This line will also not be executed" << std::endl;
}
catch (const std::string& errorMessage) {
std::cout << "Error: " << errorMessage << std::endl;
}
return 0;
}
Décortiquons les éléments clés :
Mot-clé
throw:- Utilisé pour générer une exception lorsqu'une condition spécifique est remplie
- Peut lancer différents types d'objets (chaînes de caractères, entiers, objets personnalisés)
- Arrête immédiatement l'exécution de la fonction actuelle
Bloc
try:- Contient le code qui peut générer une exception
- Vous permet d'effectuer des opérations risquées
- Si une exception se produit, le contrôle du programme passe au bloc
catchcorrespondant
Bloc
catch:- Capture et gère des types spécifiques d'exceptions
- Peut avoir plusieurs blocs
catchpour différents types d'exceptions - Empêche le programme de planter en gérant les erreurs de manière élégante
Compilez et exécutez le programme :
g++ exception_keywords.cpp -o exception_keywords
./exception_keywords
Exemple de sortie :
Valid age: 25
Error: Age cannot be negative
Error: Age is unrealistically high
Points clés concernant les mots-clés d'exception :
throwsignale une condition d'erreurtrydéfinit un bloc de code qui peut générer une exceptioncatchgère l'exception et empêche la terminaison du programme- Les exceptions offrent une manière structurée de gérer les erreurs d'exécution
Utiliser les classes d'exceptions standard (std::exception)
Dans cette étape, vous allez apprendre à propos des classes d'exceptions standard en C++ et à utiliser la hiérarchie std::exception pour gérer différents types d'erreurs d'exécution. La bibliothèque standard C++ fournit un ensemble de classes d'exceptions prédéfinies qui couvrent diverses situations d'erreur.
Ouvrez le WebIDE et créez un nouveau fichier appelé standard_exceptions.cpp dans le répertoire ~/project :
touch ~/project/standard_exceptions.cpp
Ajoutez le code suivant à standard_exceptions.cpp :
#include <iostream>
#include <stdexcept>
#include <limits>
double divideNumbers(double numerator, double denominator) {
// Check for division by zero using std::runtime_error
if (denominator == 0) {
throw std::runtime_error("Division by zero is not allowed!");
}
return numerator / denominator;
}
void checkArrayIndex(int* arr, int size, int index) {
// Check for out-of-range access using std::out_of_range
if (index < 0 || index >= size) {
throw std::out_of_range("Array index is out of bounds!");
}
std::cout << "Value at index " << index << ": " << arr[index] << std::endl;
}
int main() {
try {
// Demonstrate division by zero exception
std::cout << "Attempting division:" << std::endl;
double result = divideNumbers(10, 0);
}
catch (const std::runtime_error& e) {
std::cout << "Runtime Error: " << e.what() << std::endl;
}
try {
// Demonstrate array index out of range exception
int numbers[] = {1, 2, 3, 4, 5};
int arraySize = 5;
std::cout << "\nAccessing array elements:" << std::endl;
checkArrayIndex(numbers, arraySize, 2); // Valid index
checkArrayIndex(numbers, arraySize, 10); // Invalid index
}
catch (const std::out_of_range& e) {
std::cout << "Out of Range Error: " << e.what() << std::endl;
}
return 0;
}
Explorons les classes d'exceptions standard :
std::exception:- Classe de base pour toutes les exceptions standard
- Fournit une méthode virtuelle
what()pour obtenir la description de l'erreur
Classes d'exceptions dérivées courantes :
std::runtime_error: Pour les erreurs d'exécution qui ne peuvent être détectées qu'au cours de l'exécution du programmestd::out_of_range: Lorsqu'un index ou un itérateur est en dehors de la plage valide- D'autres classes courantes incluent
std::logic_error,std::invalid_argument, etc.
Compilez et exécutez le programme :
g++ standard_exceptions.cpp -o standard_exceptions
./standard_exceptions
Exemple de sortie :
Attempting division:
Runtime Error: Division by zero is not allowed!
Accessing array elements:
Value at index 2: 3
Out of Range Error: Array index is out of bounds!
Points clés concernant les classes d'exceptions standard :
- Offrent une manière structurée de gérer différents types d'erreurs
- Chaque classe d'exception a un objectif spécifique
- La méthode
what()retourne un message d'erreur descriptif - Aide à créer une gestion des erreurs plus robuste et informative
Définir des classes d'exceptions personnalisées
Dans cette étape, vous allez apprendre à créer vos propres classes d'exceptions personnalisées en C++. Les exceptions personnalisées vous permettent de définir des types d'erreurs spécifiques adaptés aux besoins uniques de votre application.
Ouvrez le WebIDE et créez un nouveau fichier appelé custom_exceptions.cpp dans le répertoire ~/project :
touch ~/project/custom_exceptions.cpp
Ajoutez le code suivant à custom_exceptions.cpp :
#include <iostream>
#include <string>
#include <stdexcept>
// Custom exception class for bank account errors
class InsufficientFundsException : public std::runtime_error {
public:
// Constructor that takes account balance and withdrawal amount
InsufficientFundsException(double balance, double amount)
: std::runtime_error("Insufficient funds"),
currentBalance(balance),
withdrawalAmount(amount) {}
// Method to get detailed error information
double getCurrentBalance() const { return currentBalance; }
double getWithdrawalAmount() const { return withdrawalAmount; }
private:
double currentBalance;
double withdrawalAmount;
};
class BankAccount {
private:
double balance;
public:
BankAccount(double initialBalance) : balance(initialBalance) {}
void withdraw(double amount) {
// Check if withdrawal amount exceeds current balance
if (amount > balance) {
throw InsufficientFundsException(balance, amount);
}
balance -= amount;
std::cout << "Withdrawal successful. Remaining balance: $"
<< balance << std::endl;
}
double getBalance() const { return balance; }
};
int main() {
try {
// Create a bank account with initial balance
BankAccount account(100.0);
// Attempt a valid withdrawal
account.withdraw(50.0);
// Attempt an invalid withdrawal
account.withdraw(75.0);
}
catch (const InsufficientFundsException& e) {
std::cout << "Error: " << e.what() << std::endl;
std::cout << "Current Balance: $" << e.getCurrentBalance() << std::endl;
std::cout << "Attempted Withdrawal: $" << e.getWithdrawalAmount() << std::endl;
}
return 0;
}
Décortiquons la classe d'exception personnalisée :
Hériter de
std::runtime_error:- Fournit une base pour les classes d'exceptions personnalisées
- Permet d'utiliser la méthode
what()pour obtenir la description de l'erreur
Caractéristiques des exceptions personnalisées :
- Constructeur avec un contexte d'erreur supplémentaire
- Méthodes pour récupérer des détails spécifiques sur l'erreur
- Fournit une gestion des erreurs plus informative
Compilez et exécutez le programme :
g++ custom_exceptions.cpp -o custom_exceptions
./custom_exceptions
Exemple de sortie :
Withdrawal successful. Remaining balance: $50
Error: Insufficient funds
Current Balance: $50
Attempted Withdrawal: $75
Points clés concernant les classes d'exceptions personnalisées :
- Hériter des classes d'exceptions standard
- Ajouter un contexte d'erreur spécifique et des méthodes
- Fournir des informations plus détaillées sur l'erreur
- Améliorer la gestion des erreurs et le débogage
Implémenter plusieurs blocs catch pour différents types d'exceptions
Dans cette étape, vous allez apprendre à gérer plusieurs types d'exceptions en utilisant différents blocs catch. Cette approche vous permet de fournir une gestion d'erreur spécifique pour divers types d'exceptions qui pourraient se produire dans votre programme.
Ouvrez le WebIDE et créez un nouveau fichier appelé multiple_catch.cpp dans le répertoire ~/project :
touch ~/project/multiple_catch.cpp
Ajoutez le code suivant à multiple_catch.cpp :
#include <iostream>
#include <stdexcept>
#include <string>
class InvalidAgeException : public std::runtime_error {
public:
InvalidAgeException(int age)
: std::runtime_error("Invalid age"), invalidAge(age) {}
int getInvalidAge() const { return invalidAge; }
private:
int invalidAge;
};
class Student {
private:
std::string name;
int age;
public:
void setStudent(const std::string& studentName, int studentAge) {
// Validate name length
if (studentName.length() < 2) {
throw std::length_error("Name is too short");
}
// Validate age range
if (studentAge < 0 || studentAge > 120) {
throw InvalidAgeException(studentAge);
}
name = studentName;
age = studentAge;
}
void displayInfo() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
int main() {
Student student;
// First attempt: Short name
try {
student.setStudent("A", 25);
}
catch (const std::length_error& e) {
std::cout << "Length Error: " << e.what() << std::endl;
}
catch (const InvalidAgeException& e) {
std::cout << "Age Error: " << e.what()
<< " (" << e.getInvalidAge() << ")" << std::endl;
}
// Second attempt: Invalid age
try {
student.setStudent("John Doe", 150);
}
catch (const std::length_error& e) {
std::cout << "Length Error: " << e.what() << std::endl;
}
catch (const InvalidAgeException& e) {
std::cout << "Age Error: " << e.what()
<< " (" << e.getInvalidAge() << ")" << std::endl;
}
// Successful attempt
try {
student.setStudent("Alice", 20);
student.displayInfo();
}
catch (const std::length_error& e) {
std::cout << "Length Error: " << e.what() << std::endl;
}
catch (const InvalidAgeException& e) {
std::cout << "Age Error: " << e.what()
<< " (" << e.getInvalidAge() << ")" << std::endl;
}
return 0;
}
Décortiquons les plusieurs blocs catch :
Plusieurs blocs
catch:- Permettent de gérer différents types d'exceptions
- Sont exécutés dans l'ordre du plus spécifique au plus général
- Chaque bloc peut gérer un type d'exception spécifique
Stratégie de gestion des exceptions :
- Le premier bloc
catchgèrestd::length_error - Le deuxième bloc
catchgèreInvalidAgeException - Fournit des messages d'erreur spécifiques pour différents scénarios
- Le premier bloc
Compilez et exécutez le programme :
g++ multiple_catch.cpp -o multiple_catch
./multiple_catch
Exemple de sortie :
Length Error: Name is too short
Age Error: Invalid age (150)
Name: Alice, Age: 20
Points clés concernant les plusieurs blocs catch :
- Gérer différents types d'exceptions séparément
- Fournir une gestion d'erreur spécifique pour chaque exception
- L'ordre est important lors de la capture des exceptions
- Permet une gestion plus précise des erreurs
Utiliser des blocs try-catch imbriqués
Dans cette étape, vous allez apprendre à utiliser des blocs try-catch imbriqués pour gérer des scénarios d'erreur complexes et fournir une gestion d'exceptions plus précise. Les blocs try-catch imbriqués vous permettent de gérer les exceptions à différents niveaux de votre code.
Ouvrez le WebIDE et créez un nouveau fichier appelé nested_exceptions.cpp dans le répertoire ~/project :
touch ~/project/nested_exceptions.cpp
Ajoutez le code suivant à nested_exceptions.cpp :
#include <iostream>
#include <stdexcept>
#include <string>
class FileReadError : public std::runtime_error {
public:
FileReadError(const std::string& filename)
: std::runtime_error("Error reading file"), fileName(filename) {}
std::string getFileName() const { return fileName; }
private:
std::string fileName;
};
class DataProcessor {
public:
void processFile(const std::string& filename) {
try {
// Simulate file reading
if (filename.empty()) {
throw FileReadError("Empty filename");
}
std::cout << "Reading file: " << filename << std::endl;
try {
// Simulate data processing
validateData(filename);
}
catch (const std::runtime_error& e) {
std::cout << "Inner try-catch: Data validation error" << std::endl;
std::cout << "Error details: " << e.what() << std::endl;
// Rethrow the exception to outer catch block
throw;
}
}
catch (const FileReadError& e) {
std::cout << "Outer try-catch: File read error" << std::endl;
std::cout << "Filename: " << e.getFileName() << std::endl;
}
catch (...) {
std::cout << "Caught unknown exception" << std::endl;
}
}
private:
void validateData(const std::string& filename) {
// Simulate data validation
if (filename == "corrupt.txt") {
throw std::runtime_error("Corrupt file data");
}
std::cout << "Data validation successful" << std::endl;
}
};
int main() {
DataProcessor processor;
// Scenario 1: Empty filename
std::cout << "Scenario 1: Empty Filename" << std::endl;
processor.processFile("");
// Scenario 2: Corrupt file
std::cout << "\nScenario 2: Corrupt File" << std::endl;
processor.processFile("corrupt.txt");
// Scenario 3: Valid file
std::cout << "\nScenario 3: Valid File" << std::endl;
processor.processFile("data.txt");
return 0;
}
Décortiquons les blocs try-catch imbriqués :
Bloc try-catch externe :
- Gère les exceptions au niveau du fichier
- Capture
FileReadErroret d'autres erreurs potentielles
Bloc try-catch interne :
- Gère les exceptions spécifiques au traitement des données
- Peut relancer des exceptions au bloc try-catch externe
Gestionnaire générique (
catch (...)) :- Capture toutes les exceptions inattendues
- Fournit une couche finale de gestion des erreurs
Compilez et exécutez le programme :
g++ nested_exceptions.cpp -o nested_exceptions
./nested_exceptions
Exemple de sortie :
Scenario 1: Empty Filename
Outer try-catch: File read error
Filename: Empty filename
Scenario 2: Corrupt File
Reading file: corrupt.txt
Inner try-catch: Data validation error
Error details: Corrupt file data
Scenario 3: Valid File
Reading file: data.txt
Data validation successful
Points clés concernant les blocs try-catch imbriqués :
- Fournissent plusieurs niveaux de gestion des exceptions
- Permettent une gestion plus détaillée des erreurs
- Peuvent relancer des exceptions aux blocs try-catch externes
- Utiles pour les scénarios d'erreur complexes
Résumé
Dans ce laboratoire, vous avez appris les concepts fondamentaux de la gestion des exceptions en C++. Vous avez commencé par comprendre comment lancer et capturer des exceptions de base en utilisant les mots-clés throw, try et catch. Vous avez exploré l'utilisation de la classe d'exception std::runtime_error pour gérer les erreurs de division par zéro. De plus, vous avez appris à accéder au message d'erreur à l'aide de la fonction e.what() dans le bloc catch. Ces techniques permettent de gérer les erreurs d'exécution de manière élégante et d'éviter les plantages du programme, vous permettant d'écrire des applications C++ plus robustes et fiables.



