C++ Exceptions
In C++, exceptions are a mechanism used to handle errors and other exceptional conditions that may occur during the execution of a program. The exception handling mechanism helps to manage and respond to runtime errors in a controlled way, ensuring that errors are handled gracefully and resources are cleaned up properly.
Key Concepts of Exception Handling
Throwing Exceptions: An exception is thrown when an error condition is detected. This is done using the
throwkeyword.Catching Exceptions: The thrown exception is caught using a
tryblock andcatchblocks. Thetryblock contains code that might throw an exception, while thecatchblocks handle specific types of exceptions.Exception Propagation: If an exception is not caught by the
tryblock, it propagates up the call stack to the nearest enclosingtryblock that can handle it.Finally Block: C++ does not have a
finallyblock like some other languages (e.g., Java), but the cleanup code is often placed in thecatchblock or using RAII (Resource Acquisition Is Initialization) principles.
Basic Syntax
Throwing an Exception
To throw an exception, use the throw keyword followed by an exception object:
cppthrow SomeException();
Catching an Exception
Exceptions are caught using try and catch blocks:
cpptry {
// Code that might throw an exception
} catch (const SomeException& e) {
// Code to handle the exception
} catch (...) {
// Code to handle any exception
}
Example
cpp#include
#include // For std::runtime_error
void mightGoWrong() {
bool errorOccurred = true; // Simulate an error condition
if (errorOccurred) {
throw std::runtime_error("Something went wrong!");
}
}
int main() {
try {
mightGoWrong();
} catch (const std::runtime_error& e) {
std::cout << "Caught an exception: " << e.what() << std::endl;
} catch (...) {
std::cout << "Caught an unknown exception" << std::endl;
}
return 0;
}
Custom Exceptions
You can define your own exception classes by inheriting from std::exception or one of its derived classes.
Defining a Custom Exception
cpp#include
#include
#include
class MyException : public std::exception {
private:
std::string message;
public:
MyException(const std::string& msg) : message(msg) {}
virtual const char* what() const noexcept override {
return message.c_str();
}
};
void mayThrowCustomException() {
throw MyException("This is a custom exception!");
}
int main() {
try {
mayThrowCustomException();
} catch (const MyException& e) {
std::cout << "Caught custom exception: " << e.what() << std::endl;
}
return 0;
}
Exception Safety
When writing code that might throw exceptions, you should ensure exception safety. This means making sure that your code handles exceptions without leaving the program in an inconsistent state.
Types of Exception Safety
- Basic Guarantee: The program remains in a valid state if an exception is thrown.
- Strong Guarantee: If an exception is thrown, the program state is not changed (rollback to the initial state).
- No-throw Guarantee: The function guarantees not to throw any exceptions.
RAII (Resource Acquisition Is Initialization)
RAII is a technique used in C++ to manage resources, such as memory or file handles. It ensures that resources are properly released when objects go out of scope, which helps with exception safety.
Example of RAII
cpp#include
#include
class FileWrapper {
private:
std::ofstream file;
public:
FileWrapper(const std::string& filename) : file(filename) {
if (!file) {
throw std::runtime_error("Failed to open file");
}
}
~FileWrapper() {
if (file.is_open()) {
file.close();
}
}
void write(const std::string& data) {
file << data;
}
};
int main() {
try {
FileWrapper fw("example.txt");
fw.write("Hello, World!");
} catch (const std::exception& e) {
std::cout << "Exception: " << e.what() << std::endl;
}
return 0;
}
Best Practices
- Use Standard Exceptions: Prefer using standard exception classes (e.g.,
std::runtime_error,std::out_of_range) when possible. - Catch by Reference: Catch exceptions by reference to avoid slicing and unnecessary copying.
- Handle Exceptions at Appropriate Levels: Handle exceptions at levels where you can meaningfully recover or log the issue.
- Avoid Exceptions for Control Flow: Use exceptions for exceptional conditions, not for regular control flow.