Exception Handling in C++

Exception Handling in C++

What is Exception handling in C++?

  • Exception handling in C++ is a mechanism that allows you to deal with unexpected or exceptional situations that may occur during the execution of a program.
  • These situations are often referred to as "exceptions."

Exception handling in C++ Syntax

C++, exception handling is done using the try, catch, and throw keywords. Here's the syntax for exception handling:

Throwing an Exception

To throw an exception, you use the throw keyword followed by an exception object:
1throw MyException("An error occurred");

C++ try-catch Block

The try block is used to enclose a section of code where an exception might be thrown. Afterward, there are one or more catch blocks.
1try {
2// Code that might throw an exception
3} catch (ExceptionType1 &e1) {
4// Handle ExceptionType1
5} catch (ExceptionType2 &e2) {
6// Handle ExceptionType2
7} catch (...) {
8// Handle any other exception
9}
  • In this example, we have a try block with multiple catch blocks.
  • If an exception of type ExceptionType1 is thrown, it will be captured by the initial catch block.
  • If it's ExceptionType2, it will be caught by the second catch block.
  • The ellipsis (...) in the last catch block is a generic catch that can catch any type of exception.

Catching Exception

  • Every catch block specifies the particular type of exception it can handle.
  • When an exception is thrown, the program checks each catch block to see if the thrown exception matches the specified type.
  • If it does, the corresponding catch block is executed.

Rethrowing an Exception

  • Inside a catch block, you can rethrow the same exception using throw.
  • This allows the exception to be caught and handled by an outer try-catch block or propagated up the call stack.
1try {
2// Code that might throw an exception
3} catch (ExceptionType &e) {
4// Handle the exception
5throw; // Rethrow the exception
6}

Exception Classes

  • Exception types can be built-in types or user-defined classes.
  • User-defined exception classes should typically be derived from std::exception or a related base class.
1class MyException : public std::exception {
2public:
3const char* what() const noexcept {
4return "My custom exception occurred";
5}
6};

Exception Handling in C++ Example

Example of exception handling in C++:
1#include <iostream>
2using namespace std;
3
4// Custom exception class derived from std::exception
5class MyException : public exception {
6public:
7    const char* what() const noexcept {
8        return "My custom exception occurred";
9    }
10};
11
12int main() {
13    try {
14        int x = 10, y = 0;
15
16        if (y == 0) {
17            // Throwing an exception of type MyException
18            throw MyException();
19        }
20
21        int result = x / y;
22        cout << "Result: " << result << endl;
23    } catch (const MyException &e) {
24        // Catching and handling MyException
25        cout << "Custom Exception Caught: " << e.what() << endl;
26    } catch (const exception &e) {
27        // Catching any other exception derived from std::exception
28        cout << "Standard Exception Caught: " << e.what() << endl;
29    } catch (...) {
30        // Catching any other type of exception
31        cout << "Unknown Exception Caught" << endl;
32    }
33
34    return 0;
35}
  • We define a custom exception class MyException that is derived from std::exception. It overrides the what() function to provide a custom error message.
  • In the main function, we attempt to divide x by y. If y is 0, we throw a MyException.

Types of exception in C++

  • std::exception
  • std::runtime_error
  • std::logic_error
  • std::invalid_argument
  • std::out_of_range
  • std::overflow_error
  • std::underflow_error
  • std::bad_alloc
  • std::bad_typeid
  • std::future_error

std::exception

std::exception is the base class for all standard C++ exceptions. It provides a what() function that returns a descriptive error message.

std::runtime_error

std::runtime_error is typically used to represent errors that can occur during runtime and are not easily predictable.

std::logic_error

std::logic_error is used for errors that are generally caused by a mistake in the program's logic.

std::invalid_argument

This exception is thrown when a function receives an argument of an inappropriate value.

std::out_of_range

std::out_of_range is thrown by functions that have a defined range, such as arrays or containers, and the argument provided is outside that range.

std::overflow_error

This exception is thrown when arithmetic overflow occurs.

std::underflow_error

std::underflow_error is thrown when arithmetic underflow occurs, which happens when calculations result in values too close to zero to be represented accurately. It's another subclass of std::runtime_error.

std::bad_alloc

This exception is thrown when the new operator fails to allocate memory due to insufficient memory resources.

std::bad_typeid

This exception is thrown by the typeid operator when it cannot identify the type of an object. It's useful for handling errors related to type identification.

std::future_error

std::future_error is thrown when an error occurs in a std::future or std::shared_future operation.
It's worth noting that you can also create your own custom exceptions by subclassing std::exception or one of its derived classes.

Specifying exceptions for a function

  • You can specify the types of exceptions a function might throw using the throw keyword in the function declaration.
  • Now, let's provide some simple examples:
1#include <iostream>
2using namespace std;
3
4int main() {
5    try {
6        int x = 10, y = 0;
7        if (y == 0) {
8            throw runtime_error("Divide by zero error");
9        }
10        int result = x / y;
11        cout << "Result: " << result << endl;
12    } catch (runtime_error &e) {
13        cout << "Error: " << e.what() << endl;
14    }
15
16    return 0;
17}
  • In this example, we're attempting to divide x by y.
  • If y is 0, it will throw a runtime_error with the message "Divide by zero error".
  • This exception will be caught in the catch block, and the error message will be printed.

Benefits of exception handling

  • Separation of Error Handling Code:
  • Exception handling allows you to separate the code that detects errors from the code that handles them.
  • Graceful Recovery from Errors:
  • Exceptions provide a mechanism for gracefully recovering from errors.
  • Robustness and Reliability:
  • Exception handling improves the robustness and reliability of your code.

Conclusion

Exception handling in C++ is a powerful mechanism for managing errors and exceptional situations in a program.