<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.