C++ Exception Handling: A Comprehensive Guide
In C++, exception handling is a critical mechanism for managing runtime errors and unexpected events gracefully, preventing program crashes and ensuring application stability. The core of C++ exception handling revolves around try-catch
blocks, but it also extends to custom exceptions and resource management techniques like RAII.
1. Using try-catch
Blocks
The fundamental approach to exception handling in C++ involves placing code that might throw an exception within a try
block. If an exception occurs, control is transferred to a corresponding catch
block, where the exception can be handled.
try {
// Code that might throw an exception
if (true) {
throw "An error occurred!";
}
} catch (const char* msg) {
// Handle the exception of type const char*
std::cerr << "Caught exception: " << msg << std::endl;
} catch (...) {
// Catch any other unhandled exceptions (ellipsis catch-all)
std::cerr << "Caught an unknown exception." << std::endl;
}
You can use multiple catch
blocks to handle different types of exceptions. The ellipsis (...
) catch block acts as a general handler for any exception not caught by preceding specific catch
blocks.
2. Throwing Exceptions Manually
Exceptions can be explicitly thrown using the throw
keyword. This is typically done when an error condition is detected that prevents the program from continuing normally.
void divide(int numerator, int denominator) {
if (denominator == 0) {
throw std::runtime_error("Division by zero is not allowed.");
}
// Perform division
}
3. Custom Exception Classes
For more structured and informative error handling, you can define your own custom exception classes. These classes typically inherit from standard exception classes like std::exception
, std::runtime_error
, or std::logic_error
.
class MyCustomException : public std::runtime_error {
public:
MyCustomException(const std::string& message)
: std::runtime_error(message) {}
};
// Usage: throw MyCustomException("Something went wrong!");
4. Resource Acquisition Is Initialization (RAII)
RAII is a C++ programming idiom that ties the lifecycle of a resource (like memory, file handles, or network connections) to the lifetime of an object. Resources are acquired in the object’s constructor and released in its destructor. This ensures that resources are properly cleaned up, even if an exception occurs, preventing resource leaks.
class FileHandler {
public:
FileHandler(const std::string& filename) {
// Open file (resource acquisition)
// ... throw exception if opening fails
}
~FileHandler() {
// Close file (resource release)
}
};
// Usage: FileHandler file("data.txt"); // File automatically closed when file object goes out of scope
By combining try-catch
blocks with custom exceptions and RAII, C++ developers can create robust and resilient applications that handle errors effectively and maintain resource integrity.