CSS Prepare

optional · CSS study notes

22. Exception Handling

  • try block: code that may throw an error
  • catch block: handles a specific exception type
  • throw: raises an exception

Enables graceful error recovery instead of abrupt program termination.

#include <iostream>
using namespace std;

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

int main()
{
    try                                              // try block
    {
        cout << divide(10, 0) << endl;
    }
    catch (const runtime_error& e)                    // catch block
    {
        cout << "Caught exception: " << e.what() << endl;
    }
    return 0;
}

Output: Caught exception: Division by zero! — program continues instead of crashing.

If a thrown exception has no matching catch, the program calls std::terminate() and aborts — a common CSS exam follow-up question.

Multiple catch blocks — handling different error types differently

#include <iostream>
using namespace std;

int divide(int a, int b)
{
    if (b == 0)
        throw runtime_error("Division by zero!");
    if (a < 0 || b < 0)
        throw invalid_argument("Negative numbers not allowed!");
    return a / b;
}

int main()
{
    try
    {
        cout << divide(10, 0) << endl;
    }
    catch (const invalid_argument& e)          // more specific exception type first
    {
        cout << "Invalid argument: " << e.what() << endl;
    }
    catch (const runtime_error& e)             // more general type after
    {
        cout << "Runtime error: " << e.what() << endl;
    }
    catch (...)                                 // catch-all -- catches ANY exception type not matched above
    {
        cout << "Unknown exception occurred\n";
    }

    cout << "Program continues normally\n";
    return 0;
}

Output:

Runtime error: Division by zero!
Program continues normally

Why order matters when catching multiple types

C++ checks catch blocks top-to-bottom and uses the first matching one. A catch (...) placed first would swallow every exception, making the more specific catch blocks below it unreachable — always order from most specific to most general, with catch (...) last.

What happens with NO matching catch

void riskyFunction() { throw string("oops"); }

int main()
{
    riskyFunction();   // no try/catch around this at all
    return 0;
}
// Program calls std::terminate() and crashes -- an uncaught exception always aborts the program

Important MCQs

  1. Which block contains code that might throw an exception?
    • a) catch b) try c) throw d) finally
  2. If no matching catch block exists for a thrown exception, the program:
    • a) Ignores it and continues b) Calls std::terminate() and aborts c) Automatically retries d) Converts it to a warning
  3. catch (...) should be placed:
    • a) First, before specific catch blocks b) Last, after all more specific catch blocks c) It doesn't matter d) Only in constructors
  4. Catch blocks are checked:
    • a) In random order b) Top-to-bottom, using the first matching type c) Bottom-to-top d) All simultaneously

Self-Test Questions

  1. Why must catch blocks be ordered from most specific to most general?
  2. What happens to a program when an exception is thrown but no catch block matches it?
  3. What does catch (...) do differently from catch (const runtime_error& e)?