How to throw a C++ exception
Categories:
Mastering C++ Exceptions: A Comprehensive Guide
Learn how to effectively throw and handle exceptions in C++ to write robust and error-resilient applications. This article covers the fundamentals, best practices, and common pitfalls.
Exception handling is a critical mechanism in C++ for dealing with runtime errors and unexpected situations. Instead of returning error codes that can be easily ignored, exceptions provide a structured way to transfer control from the point where an error is detected to a designated error-handling block. This approach leads to cleaner, more maintainable code, especially in complex applications.
The Basics of Throwing an Exception
In C++, you throw an exception using the throw
keyword, followed by an expression that represents the exception object. This object can be of any type, though it's best practice to throw objects of classes derived from std::exception
or custom exception classes. When an exception is thrown, the normal program flow is interrupted, and the runtime searches for a suitable catch
block.
#include <iostream>
#include <stdexcept>
void divide(int numerator, int denominator) {
if (denominator == 0) {
throw std::runtime_error("Division by zero is not allowed.");
}
std::cout << "Result: " << numerator / denominator << std::endl;
}
int main() {
try {
divide(10, 2);
divide(10, 0); // This will throw an exception
} catch (const std::runtime_error& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
A basic example demonstrating how to throw a std::runtime_error
when division by zero occurs.
const
reference. This prevents object slicing and ensures that you catch the most derived exception type.Designing Custom Exception Classes
While standard exceptions like std::runtime_error
are useful, creating custom exception classes allows for more specific error reporting and better categorization of problems. By deriving your custom exceptions from std::exception
, you can leverage its what()
method to provide a descriptive error message and integrate smoothly with existing exception handling hierarchies.
#include <iostream>
#include <stdexcept>
#include <string>
class CustomError : public std::runtime_error {
public:
CustomError(const std::string& message) : std::runtime_error(message) {}
};
void processData(int value) {
if (value < 0) {
throw CustomError("Input value cannot be negative.");
}
std::cout << "Processing value: " << value << std::endl;
}
int main() {
try {
processData(10);
processData(-5); // This will throw a custom exception
} catch (const CustomError& e) {
std::cerr << "Caught custom error: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Caught generic exception: " << e.what() << std::endl;
}
return 0;
}
Defining and throwing a custom exception class CustomError
derived from std::runtime_error
.
Flowchart of C++ Exception Handling Mechanism
When and What to Throw
Deciding when to throw an exception is crucial. Exceptions should be reserved for truly exceptional circumstances — situations that prevent a function from fulfilling its contract. They are not meant for expected control flow. As for what to throw, always prefer throwing objects that convey meaningful information about the error. Avoid throwing primitive types like int
or char*
as they lack context and type safety.
std::terminate
will be called, leading to program abortion.1. Step 1
Identify an exceptional condition where a function cannot complete its intended task.
2. Step 2
Choose an appropriate exception type (standard or custom) that accurately describes the error.
3. Step 3
Create an instance of the exception object, providing a descriptive message if applicable.
4. Step 4
Use the throw
keyword followed by the exception object to initiate stack unwinding.
5. Step 5
Ensure there is a corresponding try-catch
block higher up the call stack to handle the thrown exception.