<exception>The <exception> header is a fundamental part of the C++ Standard Library that provides support for exception handling. It defines the base class for all exceptions (std::exception) and several standard exception classes derived from it. This header is crucial for implementing robust error handling mechanisms in C++ programs, allowing for the separation of error detection and error handling code.
std::exception classstd::runtime_error, std::logic_error)std::terminate, std::set_terminate)std::nested_exception class for handling nested exceptions#include <exception>
#include <iostream>
#include <stdexcept>
double divide(double numerator, double denominator) {
if (denominator == 0) {
throw std::runtime_error("Division by zero!");
}
return numerator / denominator;
}
int main() {
try {
std::cout << "Result: " << divide(10, 2) << std::endl;
std::cout << "Result: " << divide(10, 0) << std::endl;
} catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
divide function that throws a std::runtime_error for division by zero.try block contains the code that might throw an exception.catch block catches any exception derived from std::exception.e.what() returns a C-style string describing the exception.#include <exception>
#include <string>
#include <iostream>
class CustomException : public std::exception {
private:
std::string message;
public:
explicit CustomException(const std::string& msg) : message(msg) {}
const char* what() const noexcept override {
return message.c_str();
}
};
void riskyFunction(int value) {
if (value < 0) {
throw CustomException("Negative value not allowed");
}
std::cout << "Processing value: " << value << std::endl;
}
int main() {
try {
riskyFunction(5);
riskyFunction(-1);
} catch (const CustomException& e) {
std::cerr << "Custom exception caught: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Standard exception caught: " << e.what() << std::endl;
}
return 0;
}
CustomException class derived from std::exception.what() function is overridden to return a custom error message.riskyFunction throws our custom exception for negative values.try block contains calls that might throw exceptions.catch blocks to handle different types of exceptions.#include <exception>
#include <stdexcept>
#include <iostream>
void innerFunction() {
throw std::runtime_error("Inner error");
}
void outerFunction() {
try {
innerFunction();
} catch (const std::exception& e) {
std::throw_with_nested(std::runtime_error("Outer error"));
}
}
void printException(const std::exception& e, int level = 0) {
std::cerr << std::string(level, ' ') << "Exception: " << e.what() << std::endl;
try {
std::rethrow_if_nested(e);
} catch (const std::exception& nested) {
printException(nested, level + 1);
}
}
int main() {
try {
outerFunction();
} catch (const std::exception& e) {
std::cout << "Caught exception. Hierarchy:" << std::endl;
printException(e);
}
return 0;
}
std::throw_with_nested is used to throw an exception while preserving the current exception.std::rethrow_if_nested checks if an exception is nested and rethrows it if so.printException function to display the hierarchy of nested exceptions.#include <exception>
#include <stdexcept>
#include <iostream>
#include <vector>
void demonstrateExceptions() {
std::vector<int> vec(5);
try {
// Demonstrate out_of_range
std::cout << vec.at(10) << std::endl;
} catch (const std::out_of_range& e) {
std::cerr << "Out of range error: " << e.what() << std::endl;
}
try {
// Demonstrate bad_alloc
std::vector<int> hugeVector(std::vector<int>::max_size());
} catch (const std::bad_alloc& e) {
std::cerr << "Bad allocation error: " << e.what() << std::endl;
}
try {
// Demonstrate invalid_argument
std::stoi("not a number");
} catch (const std::invalid_argument& e) {
std::cerr << "Invalid argument error: " << e.what() << std::endl;
}
}
int main() {
try {
demonstrateExceptions();
} catch (const std::exception& e) {
std::cerr << "Caught unhandled exception: " << e.what() << std::endl;
}
return 0;
}
std::out_of_range, std::bad_alloc, and std::invalid_argument.demonstrateExceptions.std::exception.Exception Safety: Ensure resources are properly managed when exceptions occur (e.g., using RAII).
Performance: Exception handling can have a performance cost, especially in tight loops.
Noexcept Specifier: Use noexcept for functions that don't throw exceptions to enable compiler optimizations.
Exception Specifications: Modern C++ discourages the use of dynamic exception specifications.
Catch by Reference: Always catch exceptions by reference to avoid slicing.
The <exception> header in C++ provides essential tools for exception handling:
std::exception class and several derived standard exceptions.std::terminate and std::set_terminate for managing program termination due to unhandled exceptions.Exception handling is a powerful mechanism for managing errors and exceptional conditions in C++ programs. It allows for the separation of error detection and error handling code, leading to cleaner and more robust software. By using the facilities provided by <exception>, developers can create more resilient applications that gracefully handle unexpected situations and provide meaningful error information to users or logging systems.
When using exceptions, it's important to consider exception safety, performance implications, and to design exception hierarchies that make sense for your application's error handling needs. Proper use of exceptions can significantly improve the reliability and maintainability of C++ code.