Exception handling is a crucial aspect of robust software development. It allows a program to deal with unexpected situations (exceptions) gracefully, ensuring that the program can continue to operate or terminate cleanly without crashing.
Key Concepts
- Exception: An event that disrupts the normal flow of the program's instructions.
- Try Block: A block of code that is tested for exceptions while it is being executed.
- Catch Block: A block of code that is executed if an exception occurs in the try block.
- Throw Statement: Used to signal the occurrence of an anomalous situation (exception).
- Exception Classes: Standard and user-defined classes that represent different types of exceptions.
Basic Syntax
Try, Catch, and Throw
try { // Code that may throw an exception } catch (exception_type1 e1) { // Code to handle exception of type exception_type1 } catch (exception_type2 e2) { // Code to handle exception of type exception_type2 } // Additional catch blocks can be added as needed
Example
#include <iostream> using namespace std; int main() { int numerator, denominator; cout << "Enter numerator: "; cin >> numerator; cout << "Enter denominator: "; cin >> denominator; try { if (denominator == 0) { throw "Division by zero error!"; } cout << "Result: " << numerator / denominator << endl; } catch (const char* msg) { cerr << "Error: " << msg << endl; } return 0; }
Explanation
- Try Block: Contains the code that might throw an exception.
- Throw Statement: Throws an exception if the denominator is zero.
- Catch Block: Catches the exception and handles it by printing an error message.
Standard Exception Classes
C++ provides several standard exception classes defined in the <stdexcept>
header. Some commonly used ones include:
Exception Class | Description |
---|---|
std::exception |
Base class for all standard exceptions |
std::runtime_error |
Represents runtime errors |
std::logic_error |
Represents logical errors |
std::out_of_range |
Represents out-of-range errors |
std::invalid_argument |
Represents invalid argument errors |
Example Using Standard Exception Classes
#include <iostream> #include <stdexcept> using namespace std; double divide(double numerator, double denominator) { if (denominator == 0) { throw runtime_error("Division by zero"); } return numerator / denominator; } int main() { double num, denom; cout << "Enter numerator: "; cin >> num; cout << "Enter denominator: "; cin >> denom; try { double result = divide(num, denom); cout << "Result: " << result << endl; } catch (runtime_error& e) { cerr << "Error: " << e.what() << endl; } return 0; }
Explanation
- Throw Statement: Throws a
runtime_error
if the denominator is zero. - Catch Block: Catches the
runtime_error
and prints the error message usinge.what()
.
Custom Exception Classes
You can define your own exception classes by inheriting from the std::exception
class.
Example
#include <iostream> #include <exception> using namespace std; class DivisionByZeroException : public exception { public: const char* what() const noexcept override { return "Division by zero exception"; } }; double divide(double numerator, double denominator) { if (denominator == 0) { throw DivisionByZeroException(); } return numerator / denominator; } int main() { double num, denom; cout << "Enter numerator: "; cin >> num; cout << "Enter denominator: "; cin >> denom; try { double result = divide(num, denom); cout << "Result: " << result << endl; } catch (DivisionByZeroException& e) { cerr << "Error: " << e.what() << endl; } return 0; }
Explanation
- Custom Exception Class:
DivisionByZeroException
inherits fromstd::exception
and overrides thewhat()
method. - Throw Statement: Throws a
DivisionByZeroException
if the denominator is zero. - Catch Block: Catches the
DivisionByZeroException
and prints the error message usinge.what()
.
Practical Exercises
Exercise 1: Basic Exception Handling
Task: Write a program that takes two integers as input and performs division. Handle the case where the denominator is zero by throwing and catching an exception.
Solution:
#include <iostream> using namespace std; int main() { int numerator, denominator; cout << "Enter numerator: "; cin >> numerator; cout << "Enter denominator: "; cin >> denominator; try { if (denominator == 0) { throw "Division by zero error!"; } cout << "Result: " << numerator / denominator << endl; } catch (const char* msg) { cerr << "Error: " << msg << endl; } return 0; }
Exercise 2: Using Standard Exception Classes
Task: Modify the above program to use std::runtime_error
for exception handling.
Solution:
#include <iostream> #include <stdexcept> using namespace std; int main() { int numerator, denominator; cout << "Enter numerator: "; cin >> numerator; cout << "Enter denominator: "; cin >> denominator; try { if (denominator == 0) { throw runtime_error("Division by zero error!"); } cout << "Result: " << numerator / denominator << endl; } catch (runtime_error& e) { cerr << "Error: " << e.what() << endl; } return 0; }
Exercise 3: Custom Exception Class
Task: Create a custom exception class for division by zero and use it in your program.
Solution:
#include <iostream> #include <exception> using namespace std; class DivisionByZeroException : public exception { public: const char* what() const noexcept override { return "Division by zero exception"; } }; int main() { int numerator, denominator; cout << "Enter numerator: "; cin >> numerator; cout << "Enter denominator: "; cin >> denominator; try { if (denominator == 0) { throw DivisionByZeroException(); } cout << "Result: " << numerator / denominator << endl; } catch (DivisionByZeroException& e) { cerr << "Error: " << e.what() << endl; } return 0; }
Common Mistakes and Tips
- Not Catching Exceptions: Always ensure that exceptions are caught to prevent the program from crashing.
- Throwing Exceptions in Destructors: Avoid throwing exceptions in destructors as it can lead to undefined behavior.
- Using Generic Catch Blocks: Be specific with catch blocks to handle different types of exceptions appropriately.
Conclusion
Exception handling is a powerful feature in C++ that helps in creating robust and error-resistant programs. By using try, catch, and throw statements, along with standard and custom exception classes, you can manage errors effectively and ensure your program behaves predictably even in unexpected situations.
C++ Programming Course
Module 1: Introduction to C++
- Introduction to C++
- Setting Up the Development Environment
- Basic Syntax and Structure
- Variables and Data Types
- Input and Output
Module 2: Control Structures
Module 3: Functions
Module 4: Arrays and Strings
Module 5: Pointers and References
- Introduction to Pointers
- Pointer Arithmetic
- Pointers and Arrays
- References
- Dynamic Memory Allocation
Module 6: Object-Oriented Programming
- Introduction to OOP
- Classes and Objects
- Constructors and Destructors
- Inheritance
- Polymorphism
- Encapsulation and Abstraction
Module 7: Advanced Topics
- Templates
- Exception Handling
- File I/O
- Standard Template Library (STL)
- Lambda Expressions
- Multithreading