In this section of our Computer Programming with C++ course, we explore how to throw exceptions from within a function. This is a critical aspect of exception handling, which allows us to signal that an error or unexpected situation has occurred during a function's execution.
Throwing an exception is the process of signaling an error or other unusual circumstance that has occurred. In C++, this is done using the throw
keyword, followed by an exception object.
Exceptions provide a way to react to exceptional circumstances (like runtime errors) in a controlled way. When a function encounters a situation it can't handle:
- It can return an error code (traditional error handling).
- It can handle the situation internally (if possible).
- Or, it can throw an exception, signaling the calling code to handle the situation.
Throwing exceptions allows us to separate error handling from our business logic, making the code cleaner and more maintainable.
- Throwing Exceptions: The syntax for throwing exceptions, including how to throw standard exceptions and custom exceptions.
- Exception Propagation: How exceptions are propagated up the call stack until they are caught by a suitable catch handler.
- No-Throw Guarantee: Functions can also provide a guarantee that they won't throw any exceptions, which is important for certain types of applications.
C++ standard library provides a set of standard exception classes that can be used to represent common problems. They are all derived from std::exception
.
#include <iostream>
#include <stdexcept>
void processInput(int input) {
if (input < 0) {
// Throw a standard exception if input is negative
throw std::domain_error("Input must be non-negative");
}
// Process the positive input
std::cout << "Processing input: " << input << std::endl;
}
int main() {
try {
processInput(-1);
} catch (const std::exception& e) {
std::cerr << "An error occurred: " << e.what() << std::endl;
}
return 0;
}
- We have a function
processInput
that throws astd::domain_error
, which is a standard exception class, when it receives a negative input. - In the
main
function, we callprocessInput
inside atry
block and provide acatch
block that catches exceptions of typestd::exception
(the base class for all standard exceptions).
Sometimes, the standard exceptions do not fit the error that has occurred. In such cases, we can define our own exception classes.
#include <iostream>
#include <exception>
// Define a custom exception class
class MyException : public std::exception {
public:
const char* what() const throw() {
return "Custom Exception: Something went wrong!";
}
};
void riskyFunction() {
// Logic that might throw an exception
throw MyException();
}
int main() {
try {
riskyFunction();
} catch (const MyException& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
- A custom exception class
MyException
is defined, which overrides thewhat()
method fromstd::exception
. riskyFunction
throws an exception of typeMyException
.- The
main
function contains a try-catch block that specifically catchesMyException
.
- Only throw exceptions for conditions that are truly exceptional and not expected to occur as part of the normal operation of the program.
- Prefer to throw objects of classes derived from
std::exception
. This ensures compatibility with other C++ code and libraries. - Catch exceptions by const reference to avoid slicing and unnecessary copying.
Throwing exceptions from functions is a powerful feature in C++ that allows for robust error handling. It's essential to understand this mechanism to write reliable applications that can handle unexpected events gracefully.