Exception Handling in C++

Exception handling in C++ provides a way to manage errors and exceptional circumstances in a program. By using the try, catch, and throw keywords, C++ enables developers to detect, handle, and recover from runtime errors gracefully, ensuring program stability and readability.


Overview of C++ Exception Handling

  • try: Defines a block of code to test for exceptions.
  • throw: Signals an exception when an error is encountered.
  • catch: Defines a block of code to handle specific exceptions.

Syntax for C++ Exception Handling

</>
Copy
try {
    // Code that may throw an exception
    throw exception;
} catch (Type1 e1) {
    // Handle exception of Type1
} catch (Type2 e2) {
    // Handle exception of Type2
}
// Optional: catch-all handler
catch (...) {
    // Handle any type of exception
}

Examples of C++ Exception Handling

Example 1: Basic Exception Handling

This example demonstrates the basics of exception handling using try, throw, and catch blocks.

</>
Copy
#include <iostream>

int main() {
    try {
        int num1 = 10, num2 = 0;
        if (num2 == 0)
            throw "Division by zero error!";
        std::cout << num1 / num2 << std::endl;
    } catch (const char* e) {
        std::cerr << "Exception caught: " << e << std::endl;
    }
    return 0;
}

Working of this Program:

  1. Include necessary headers:
    • <iostream>: Used for input/output operations.
  2. Initialize two variables:
    • The program initializes two integers: num1 with the value 10 and num2 with the value 0.
  3. Check for division by zero:
    • The program uses an if condition to check if num2 is equal to 0.
    • If num2 is 0, a throw statement is executed to raise an exception with the message "Division by zero error!".
  4. Handle the exception:
    • The program uses a catch block to handle the exception.
    • The catch block captures the exception as a const char* (a string literal).
    • The exception message is displayed using std::cerr, which outputs the error message to the standard error stream.
  5. Output the result:
    • If no exception occurs, the result of the division num1 / num2 is printed using std::cout.
    • If an exception occurs (as in this case, since num2 is 0), the error message "Division by zero error!" is displayed.

Output:

Exception caught: Division by zero error!

Example 2: Handling Multiple Exceptions

This example demonstrates handling multiple types of exceptions.

</>
Copy
#include <iostream>
#include <stdexcept>

int main() {
    try {
        int num = -1;
        if (num < 0)
            throw std::invalid_argument("Negative number not allowed!");
        else if (num == 0)
            throw std::runtime_error("Zero encountered!");
    } catch (const std::invalid_argument& e) {
        std::cerr << "Invalid Argument: " << e.what() << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
    return 0;
}

Working of this Program:

  1. Include necessary headers:
    • <iostream>: Used for input/output operations.
    • <stdexcept>: Provides standard exception classes such as std::invalid_argument and std::runtime_error.
  2. Initialize a variable:
    • An integer variable num is initialized with the value -1.
  3. Check for invalid conditions:
    • The program checks if num is less than 0 using an if statement.
    • If the condition is true, a std::invalid_argument exception is thrown with the message "Negative number not allowed!".
    • Next, it checks if num is equal to 0 using an else if statement.
    • If num equals 0, a std::runtime_error exception is thrown with the message "Zero encountered!".
  4. Handle exceptions:
    • The program uses a try-catch block to handle exceptions.
    • The first catch block handles exceptions of type std::invalid_argument and displays the message "Invalid Argument:" followed by the exception’s message using e.what().
    • The second catch block handles all other exceptions of type std::exception and displays the message "Exception:" followed by the exception’s message using e.what().

Output:

Invalid Argument: Negative number not allowed!

Best Practices for Exception Handling

  • Use exceptions only for exceptional circumstances, not normal control flow.
  • Always catch exceptions by reference to avoid slicing.
  • Provide meaningful error messages when throwing exceptions.
  • Use standard exceptions like std::runtime_error and std::invalid_argument where applicable.
  • Avoid throwing exceptions in destructors, as they may lead to undefined behavior.

Advanced Topics in Exception Handling

For more complex scenarios, consider these advanced techniques:

  • Custom Exception Classes: Define your own exception classes to represent domain-specific errors.
  • Exception Safety: Ensure your code adheres to exception safety guarantees, such as strong or basic exception safety.
  • Re-throwing Exceptions: Use throw; to re-throw an exception from a catch block.