C++ Exceptions
advancedPart of Advanced C++
Theory
Exceptions provide a way to handle runtime errors gracefully, separating error handling from normal program logic.
try / catch / throw
try {
int age;
std::cin >> age;
if (age < 0) {
throw std::invalid_argument("Age cannot be negative");
}
} catch (const std::invalid_argument& e) {
std::cerr << "Error: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "General error: " << e.what() << std::endl;
}Catch blocks are checked in order. Always catch derived classes before base classes.
Standard Exception Hierarchy
All standard exceptions derive from std::exception:
std::runtime_error— errors detectable at runtimestd::logic_error— errors detectable before runtimestd::invalid_argument— invalid argument valuesstd::out_of_range— index out of boundsstd::bad_alloc— memory allocation failure
Custom Exceptions
Create custom exception classes by inheriting from std::exception:
class InsufficientFunds : public std::exception {
public:
const char* what() const noexcept override {
return "Insufficient funds for withdrawal";
}
};RAII and Exceptions
RAII (Resource Acquisition Is Initialization) ties resource lifetime to object lifetime. When an exception causes stack unwinding, RAII objects are automatically destroyed, preventing resource leaks:
The noexcept Specifier
noexcept declares that a function does not throw exceptions:
int add(int a, int b) noexcept {
return a + b;
}The compiler can optimize noexcept functions better. Destructors and move operations should typically be noexcept.
Practical Examples
Exercises
Bank Account with Exception Handling
Create a BankAccount class where withdraw() throws custom exceptions for insufficient funds and negative amounts. Use RAII for a transaction log.
Expected Output:
Deposited $500. Withdrew $200. Attempted overdraft: Insufficient funds.