CodeNebula
C++98corebeginner

Exception Handling

C++98 · The Foundation · Compiler flag: -std=c++98

Explanation

Handles errors using `try`, `catch`, and `throw`.

Real-World Scenario

Handle file not found errors in a data processing app.

Quick Snippet

snippet.cpp
try { throw "Error"; } catch(const char* msg) {}

Full Example

exception_handling.cpp
// CodeNebula - C++98 Example: Exception Handling
// Compile: g++ -std=c++98 -Wall -Wextra -o example exception_handling.cpp

// Exception handling in C++98 uses try/catch/throw to separate error handling
// from normal logic. This example covers: throwing built-in types, standard
// exceptions, custom exception hierarchies, multiple catch blocks, catch-all,
// and exception propagation through the call stack.

#include <iostream>
#include <string>
#include <stdexcept>   // std::runtime_error, std::out_of_range, etc.
#include <cstdio>     // std::sprintf
#include <cmath>

// ------------------------------------------------------------------
// Custom exception hierarchy
// ------------------------------------------------------------------
class AppException {
private:
    std::string message;
public:
    AppException(const std::string& msg) : message(msg) {}
    virtual ~AppException() {}
    virtual std::string what() const { return message; }
};

class FileException : public AppException {
private:
    std::string filename;
public:
    FileException(const std::string& fname, const std::string& msg)
        : AppException(msg), filename(fname) {}
    std::string getFilename() const { return filename; }
    std::string what() const {
        return "FileException [" + filename + "]: " + AppException::what();
    }
};

class NetworkException : public AppException {
private:
    int errorCode;
public:
    NetworkException(int code, const std::string& msg)
        : AppException(msg), errorCode(code) {}
    int getErrorCode() const { return errorCode; }
    std::string what() const {
        // Build the string manually (no std::to_string in C++98)
        std::string result = "NetworkException (code ";
        // Simple int-to-string for small numbers
        char buf[32];
        std::sprintf(buf, "%d", errorCode);
        result += buf;
        result += "): " + AppException::what();
        return result;
    }
};

// ------------------------------------------------------------------
// Functions that throw exceptions
// ------------------------------------------------------------------
double safeDivide(double a, double b) {
    if (b == 0.0) {
        throw std::runtime_error("Division by zero");
    }
    return a / b;
}

int safeArrayAccess(int arr[], int size, int index) {
    if (index < 0 || index >= size) {
        throw std::out_of_range("Array index out of bounds");
    }
    return arr[index];
}

void openFile(const std::string& name) {
    // Simulate a file not found scenario
    throw FileException(name, "File not found");
}

void connectToServer(const std::string& host) {
    // Simulate a network failure
    throw NetworkException(404, std::string("Cannot reach ") + host);
}

// Function that demonstrates exception propagation
void processData() {
    std::cout << "  processData: calling safeDivide(10, 0)..." << std::endl;
    double result = safeDivide(10, 0);  // This will throw
    std::cout << "  This line never executes. result=" << result << std::endl;
}

int main() {
    std::cout << "=== C++98 Exception Handling ===" << std::endl;

    // --- 1. Basic try/catch with std::runtime_error ---
    std::cout << "\n--- 1. Division by zero ---" << std::endl;
    try {
        double r = safeDivide(10.0, 3.0);
        std::cout << "10 / 3 = " << r << std::endl;
        // Expected: 10 / 3 = 3.33333

        r = safeDivide(10.0, 0.0);  // Throws!
        std::cout << "This won't print: " << r << std::endl;
    }
    catch (const std::runtime_error& e) {
        std::cout << "Caught runtime_error: " << e.what() << std::endl;
        // Expected: Caught runtime_error: Division by zero
    }

    // --- 2. std::out_of_range ---
    std::cout << "\n--- 2. Array bounds check ---" << std::endl;
    try {
        int arr[] = {10, 20, 30};
        std::cout << "arr[1] = " << safeArrayAccess(arr, 3, 1) << std::endl;
        // Expected: arr[1] = 20
        std::cout << "arr[5] = " << safeArrayAccess(arr, 3, 5) << std::endl;
    }
    catch (const std::out_of_range& e) {
        std::cout << "Caught out_of_range: " << e.what() << std::endl;
        // Expected: Caught out_of_range: Array index out of bounds
    }

    // --- 3. Multiple catch blocks ---
    std::cout << "\n--- 3. Multiple catch blocks ---" << std::endl;
    for (int scenario = 0; scenario < 3; ++scenario) {
        try {
            if (scenario == 0) {
                throw 42;                 // throw an int
            } else if (scenario == 1) {
                throw std::string("string exception");  // throw a string
            } else {
                throw 3.14;              // throw a double
            }
        }
        catch (int val) {
            std::cout << "Caught int: " << val << std::endl;
        }
        catch (const std::string& s) {
            std::cout << "Caught string: " << s << std::endl;
        }
        catch (...) {
            // Catch-all handler
            std::cout << "Caught unknown exception type" << std::endl;
        }
    }
    // Expected:
    // Caught int: 42
    // Caught string: string exception
    // Caught unknown exception type

    // --- 4. Custom exception hierarchy ---
    std::cout << "\n--- 4. Custom exceptions ---" << std::endl;
    try {
        openFile("data.txt");
    }
    catch (const FileException& e) {
        std::cout << e.what() << std::endl;
        std::cout << "File was: " << e.getFilename() << std::endl;
    }
    catch (const AppException& e) {
        std::cout << "AppException: " << e.what() << std::endl;
    }
    // Expected:
    // FileException [data.txt]: File not found
    // File was: data.txt

    try {
        connectToServer("example.com");
    }
    catch (const NetworkException& e) {
        std::cout << e.what() << std::endl;
        std::cout << "Error code: " << e.getErrorCode() << std::endl;
    }
    catch (const AppException& e) {
        std::cout << "AppException: " << e.what() << std::endl;
    }
    // Expected:
    // NetworkException (code 404): Cannot reach example.com
    // Error code: 404

    // --- 5. Exception propagation through the call stack ---
    std::cout << "\n--- 5. Exception propagation ---" << std::endl;
    try {
        std::cout << "main: calling processData()..." << std::endl;
        processData();  // Internally calls safeDivide which throws
    }
    catch (const std::runtime_error& e) {
        std::cout << "main caught propagated exception: " << e.what() << std::endl;
    }
    // Expected:
    // main: calling processData()...
    //   processData: calling safeDivide(10, 0)...
    // main caught propagated exception: Division by zero

    // --- 6. Nested try/catch ---
    std::cout << "\n--- 6. Nested try/catch ---" << std::endl;
    try {
        std::cout << "Outer try block" << std::endl;
        try {
            std::cout << "Inner try block - throwing..." << std::endl;
            throw std::runtime_error("inner error");
        }
        catch (const std::runtime_error& e) {
            std::cout << "Inner catch: " << e.what() << std::endl;
            // Re-throw to outer handler
            throw;
        }
    }
    catch (const std::runtime_error& e) {
        std::cout << "Outer catch (re-thrown): " << e.what() << std::endl;
    }

    std::cout << "\nProgram completed normally." << std::endl;

    return 0;
}

/*
Expected Output:
=== C++98 Exception Handling ===

--- 1. Division by zero ---
10 / 3 = 3.33333
Caught runtime_error: Division by zero

--- 2. Array bounds check ---
arr[1] = 20
Caught out_of_range: Array index out of bounds

--- 3. Multiple catch blocks ---
Caught int: 42
Caught string: string exception
Caught unknown exception type

--- 4. Custom exceptions ---
FileException [data.txt]: File not found
File was: data.txt
NetworkException (code 404): Cannot reach example.com
Error code: 404

--- 5. Exception propagation ---
main: calling processData()...
  processData: calling safeDivide(10, 0)...
main caught propagated exception: Division by zero

--- 6. Nested try/catch ---
Outer try block
Inner try block - throwing...
Inner catch: inner error
Outer catch (re-thrown): inner error

Program completed normally.
*/
Run command
g++ -std=c++98 -Wall -Wextra -o example exception_handling.cpp