Home C++ C++ exception handling tutorial with code examples

C++ exception handling tutorial with code examples

In C++, exception handling provides a way to manage runtime errors gracefully, ensuring that the program can handle unexpected situations without crashing. The C++ standard library uses three main keywords for exception handling:

  1. try: Block of code that may cause an exception.
  2. throw: Used to raise an exception.
  3. catch: Block that handles the exception if it is thrown.

Using these keywords, you can handle errors and exceptions in a controlled manner.

Basic Syntax

try {
    // Code that may throw an exception
    throw exception_type; // Raising an exception
} catch (exception_type variable) {
    // Code to handle the exception
}

1. Basic Example of Exception Handling

This example demonstrates a basic try-catch block.

#include <iostream>
using namespace std;

int main() {
    try {
        int x = 5;
        int y = 0;
        if (y == 0) {
            throw "Division by zero error!";
        }
        cout << x / y << endl;
    } catch (const char* e) {
        cout << "Error: " << e << endl;
    }

    return 0;
}

Explanation:

  • throw “Division by zero error!”; raises an exception if y is 0.
  • The catch block catches the exception and displays an error message.

Output:

Error: Division by zero error!

2. Throwing and Catching Integer Exceptions

You can throw and catch integer exceptions to handle errors more specifically.

#include <iostream>
using namespace std;

int main() {
    try {
        int value = -1;
        if (value < 0) {
            throw value; // Throw an integer exception
        }
    } catch (int e) {
        cout << "Error: Negative value encountered (" << e << ")" << endl;
    }

    return 0;
}

Explanation:

  • An integer exception is thrown with throw value if value is negative.
  • The catch block receives the integer exception and displays the value.

Output:

Error: Negative value encountered (-1)

3. Catching Multiple Exception Types

You can have multiple catch blocks to handle different types of exceptions.

#include <iostream>
using namespace std;

int main() {
    try {
        int option = 2;
        if (option == 1) {
            throw "A string exception!";
        } else if (option == 2) {
            throw 404;
        }
    } catch (const char* e) {
        cout << "String Exception: " << e << endl;
    } catch (int e) {
        cout << "Integer Exception: Error code " << e << endl;
    }

    return 0;
}

Explanation:

  • The try block throws different exceptions based on option.
  • Multiple catch blocks handle each exception type accordingly.

Output:

Integer Exception: Error code 404

4. Catching All Exceptions with catch(…)

You can catch all exceptions using catch(…), which acts as a generic catch block.

#include <iostream>
using namespace std;

int main() {
    try {
        throw 3.14; // Throwing a double exception
    } catch (...) {
        cout << "An exception occurred" << endl;
    }

    return 0;
}

Explanation:

  • catch(…) catches any exception type, making it a catch-all block.
  • This can be useful as a fallback if specific handlers aren’t defined.

Output:

An exception occurred

5. Exception Handling with Classes

You can define custom exception classes to represent specific error conditions.

#include <iostream>
#include <string>
using namespace std;

class MyException {
public:
    string message;
    MyException(string msg) : message(msg) {}
};

int main() {
    try {
        throw MyException("Custom exception thrown!");
    } catch (MyException& e) {
        cout << "Caught exception: " << e.message << endl;
    }

    return 0;
}

Explanation:

  • MyException is a custom exception class with a message attribute.
  • The catch block catches exceptions of type MyException and displays the message.

Output:

Caught exception: Custom exception thrown!

6. Exception Handling in Functions

Functions can throw exceptions, which can be caught by the caller.

#include <iostream>
using namespace std;

void checkNumber(int number) {
    if (number < 0) {
        throw "Negative numbers are not allowed!";
    }
    cout << "Number: " << number << endl;
}

int main() {
    try {
        checkNumber(-5);
    } catch (const char* e) {
        cout << "Error: " << e << endl;
    }

    return 0;
}

Explanation:

  • checkNumber throws an exception if number is negative.
  • The exception is caught in main, where the function is called.

Output:

Error: Negative numbers are not allowed!

7. Using std::exception as a Base Class

The C++ standard library provides the std::exception class as a base for standard exceptions.

#include <iostream>
#include <exception>
using namespace std;

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

int main() {
    try {
        throw CustomException();
    } catch (exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

Explanation:

  • CustomException inherits from std::exception and overrides what() to provide a custom message.
  • what() is called in the catch block to display the error message.

Output:

Custom exception occurred!

8. Nested Try-Catch Blocks

You can nest try-catch blocks, allowing more granular error handling.

#include <iostream>
using namespace std;

int main() {
    try {
        try {
            throw "Inner exception";
        } catch (const char* e) {
            cout << "Caught in inner catch: " << e << endl;
            throw; // Rethrow to outer catch
        }
    } catch (...) {
        cout << "Caught in outer catch" << endl;
    }

    return 0;
}

Explanation:

  • The inner try block throws an exception, which is caught and rethrown to the outer try-catch.
  • The outer catch block catches the rethrown exception.

Output:

Caught in inner catch: Inner exception
Caught in outer catch

9. Rethrowing Exceptions

An exception caught in one catch block can be rethrown to be handled by an outer catch block.

#include <iostream>
using namespace std;

void func() {
    try {
        throw "Exception from func";
    } catch (const char* e) {
        cout << "Caught in func: " << e << endl;
        throw; // Rethrow exception
    }
}

int main() {
    try {
        func();
    } catch (const char* e) {
        cout << "Caught in main: " << e << endl;
    }

    return 0;
}

Explanation:

  • func catches and then rethrows an exception, which is later caught in main.

Output:

Caught in func: Exception from func
Caught in main: Exception from func

10. Using std::terminate with Uncaught Exceptions

If an exception is thrown but not caught, the program calls std::terminate.

#include <iostream>
#include <exception>
using namespace std;

void customTerminate() {
    cout << "Uncaught exception. Terminating program..." << endl;
    exit(1);
}

int main() {
    set_terminate(customTerminate);

    try {
        throw 1;
    } catch (const char* e) {
        cout << "Caught exception: " << e << endl;
    }

    return 0;
}

Explanation:

  • set_terminate(customTerminate) sets a custom handler for uncaught exceptions.
  • Since no catch block handles the integer exception, customTerminate is called.

Output:

Uncaught exception. Terminating program...

11. Exception Specification (noexcept)

You can use noexcept to specify that a function does not throw exceptions.

#include <iostream>
using namespace std;

void func() noexcept {
    cout << "This function does not throw exceptions." << endl;
}

int main() {
    try {
        func();
    } catch (...) {
        cout << "Caught exception" << endl;
    }

    return 0;
}

Explanation:

  • noexcept indicates that func does not throw exceptions.
  • This can be useful for optimization and ensuring that certain functions are exception-free.

Output:

This function does not throw exceptions.

 

Summary Table of Exception Handling Examples

Example Description
Basic Exception Handling Simple try-catch with throw
Integer Exception Throwing and catching integer exceptions
Multiple Exception Types Using multiple catch blocks for different types
Catching All Exceptions Using catch(...) to catch any exception
Custom Exception Class Defining and catching a custom exception class
Exception Handling in Functions Throwing exceptions from functions
std::exception Base Class Using std::exception as a base class for custom exceptions
Nested Try-Catch Blocks Handling exceptions with nested try-catch
Rethrowing Exceptions Rethrowing exceptions for outer handling
Using std::terminate Handling uncaught exceptions with std::terminate
noexcept Specification Indicating that a function does not throw exceptions

 

Key Takeaways

  • Exception handling in C++ helps manage runtime errors gracefully.
  • try-throw-catch mechanism: try encloses risky code, throw raises exceptions, and catch handles them.
  • You can create custom exception classes to represent specific errors.
  • Multiple catch blocks allow handling different exception types, and catch(…) provides a catch-all handler.
  • noexcept specifies that a function does not throw exceptions, which can improve performance.
  • Best practices include defining meaningful custom exceptions, rethrowing exceptions where appropriate, and avoiding using exceptions for regular control flow.

You may also like