Advanced C++

Exception Handling in C++ – Writing Robust Programs

Learn how to gracefully handle runtime errors using try, catch, and throw. Master standard exceptions, custom exceptions, and best practices for clean, maintainable error-handling code.

By Arj Updated July 2025 12 min read Advanced C++
What you'll learn
  • What exception handling is and why it matters
  • How to use try, catch, and throw effectively
  • The standard exception classes in C++
  • How to create custom exception classes
  • Best practices for writing robust error-handling code

1What is exception handling?

In real-world software, things can go wrong: a file might not open, a network might fail, or an invalid value might sneak into your program. Exception handling is a key feature in C++ that allows you to gracefully manage such errors without crashing the entire program.

Rather than using return codes or flags, C++ lets you throw exceptions when something goes wrong, and catch them where you can respond appropriately.

2Basic syntax

cpp
try {
    // Code that may throw an exception
} catch (exception_type variable) {
    // Code that handles the exception
}

Example: Division by zero

cpp
#include <iostream>
using namespace std;

int divide(int a, int b) {
    if (b == 0)
        throw "Division by zero!";
    return a / b;
}

int main() {
    try {
        int result = divide(10, 0);
        cout << "Result: " << result << endl;
    } catch (const char* msg) {
        cout << "Error: " << msg << endl;
    }
    return 0;
}
OutputError: Division by zero!

3The throw keyword

You use throw to signal that an exception has occurred.

cpp
throw value; // value can be an int, string, object, etc.

Examples:

  • throw -1; – throws an int
  • throw "Invalid input"; – throws a C‑string
  • throw std::runtime_error("File not found"); – throws a standard exception object

4The try and catch blocks

Put all code that might throw an exception inside a try block. The catch block handles the error.

Multiple catch blocks

cpp
try {
    throw 3.14;
} catch (int e) {
    cout << "Caught int: " << e << endl;
} catch (double e) {
    cout << "Caught double: " << e << endl;
} catch (...) {
    cout << "Caught unknown exception." << endl;
}
OutputCaught double: 3.14
Catch‑all handler
The catch (...) block catches any exception type. It should be used as a last resort and placed after all other catch blocks.

5Standard exceptions in C++

C++ provides a set of predefined exception classes in the <stdexcept> header.

Exception classDescription
std::runtime_errorErrors that occur at runtime
std::invalid_argumentInvalid argument passed to a function
std::out_of_rangeIndex out of range (e.g., vector access)
std::overflow_errorArithmetic overflow
std::underflow_errorArithmetic underflow
std::logic_errorErrors in program logic
cpp
#include <iostream>
#include <stdexcept>
using namespace std;

int main() {
    try {
        throw std::out_of_range("Index out of range!");
    } catch (const std::exception& e) {
        cout << "Caught exception: " << e.what() << endl;
    }
    return 0;
}
OutputCaught exception: Index out of range!
Catch by reference
Catching std::exception by reference (const std::exception&) avoids slicing and enables polymorphic behavior.

6Custom exception classes

You can define your own exception class by inheriting from std::exception.

cpp
class MyException : public std::exception {
public:
    const char* what() const noexcept override {
        return "Custom exception occurred!";
    }
};

Use it like this: throw MyException();

Override what()
Override the what() member function to provide a descriptive error message. The noexcept specifier ensures it does not throw.

7Nested try-catch blocks

You can nest try-catch blocks for fine‑grained error handling. You can also rethrow an exception using throw;.

cpp
try {
    try {
        throw 100;
    } catch (int x) {
        cout << "Inner catch: " << x << endl;
        throw; // rethrow
    }
} catch (...) {
    cout << "Outer catch." << endl;
}
OutputInner catch: 100 Outer catch.

8Best practices

  • Throw exceptions, don't return error codes – exceptions are more expressive and cannot be ignored accidentally.
  • Use standard exceptions where possible – they are well-tested and familiar to other developers.
  • Catch exceptions by reference – especially for objects, to avoid slicing.
  • Avoid exception handling in performance‑critical code – only if not needed, because throwing and catching have overhead.
  • Use RAII (Resource Acquisition Is Initialization) to avoid memory leaks on exceptions.
  • Never throw exceptions from destructors – they can cause program termination.
Important
Throwing from a destructor is dangerous because destructors are called during stack unwinding. If another exception is already active, the program will terminate immediately.

9Key concepts check

Try it yourself
  1. Write a function that divides two integers and throws an exception if the denominator is zero.
  2. Create a try-catch block that catches the exception and prints a friendly error message.
  3. Define a custom exception class that inherits from std::exception and override what().
  4. Throw and catch your custom exception in a program.

Bonus: Use nested try-catch blocks to handle different exception types and rethrow one of them.

10Quiz yourself

Exception Handling Quiz
Question 1 of 10

Final thoughts

Exception handling in C++ allows you to write safer, more robust applications by properly managing unexpected runtime errors. It is essential in real‑world development where external inputs, resources, and logic can often go wrong.

Understanding how to use try, catch, and throw – along with proper exception design – is a fundamental part of writing professional‑grade C++ code.

Stop wrestling with confusion.

Join thousands of students mastering Computer Science without the academic jargon.

From syntax to systems. We break down the hardest ideas in computer science so you can actually build things.

© 2026 Painless Programming. Built for students.
Scroll to Top