Exception Handling

এক্সেপশন হ্যান্ডলিং

Read: ~30 min 12 practice problems

1. try / catch / throw

tryc.cpp
#include <iostream>
#include <stdexcept>

int divide(int a, int b) {
    if (b == 0) throw std::invalid_argument{"divide by zero"};
    return a / b;
}

int main() {
    try {
        std::cout << divide(10, 0) << "\n";
    } catch (const std::invalid_argument& e) {
        std::cerr << "Caught: " << e.what() << "\n";
    } catch (const std::exception& e) {
        std::cerr << "Other: " << e.what() << "\n";
    }
}

2. The Standard Exception Hierarchy

Common types — all derived from std::exception
  • std::logic_error: invalid_argument, domain_error, length_error, out_of_range
  • std::runtime_error: range_error, overflow_error, underflow_error
  • std::bad_alloc, std::bad_cast

3. Always Catch by const Reference

Catch const std::exception& By value → slicing. By non-const ref → can't bind to temp. const T& is correct.

4. noexcept

Marks a function as guaranteed not to throw. The compiler can optimize, and STL containers use it for move-on-reallocate decisions.

noexcept.cpp
int add(int a, int b) noexcept { return a + b; }

5. Stack Unwinding & RAII

When an exception propagates up, every local object whose scope is exited has its destructor run. That's why RAII makes exception-safe code automatic — your resources clean themselves up.

6. Exception Safety Levels

  • No-throw guarantee: function never throws.
  • Strong guarantee: if it throws, state is unchanged (atomic-like).
  • Basic guarantee: if it throws, no leaks but state may be different.
  • No guarantee: avoid this.

7. When NOT to Use Exceptions

  • For normal control flow (e.g. parsing every number in a file)
  • In real-time systems with strict latency budgets
  • When the project has a "no exceptions" rule (game engines, embedded)

For "expected failure" use std::optional, std::expected (C++23), or error codes.

8. Practice Problems

  1. Write a function that throws on negative input.
    ✨ Show Answer
    int sqrt_int(int n) {
        if (n < 0) throw std::domain_error{"negative"};
        return (int)std::sqrt(n);
    }
  2. Catch all exceptions.
    ✨ Show Answer
    catch (...) { /* fallback */ }
  3. Why catch by const reference?
    ✨ Show Answer

    By value slices polymorphic exceptions. By const ref preserves the dynamic type and avoids copies.

  4. Define your own exception class.
    ✨ Show Answer
    class ParseError : public std::runtime_error {
    public:
        using std::runtime_error::runtime_error;
    };
    throw ParseError{"bad token"};
  5. What happens if no catch matches?
    ✨ Show Answer

    std::terminate is called → process aborts. Always have a top-level catch in main.

  6. Mark a destructor as noexcept(false). Why is this dangerous?
    ✨ Show Answer

    If a destructor throws during stack unwinding (caused by another exception), std::terminate is called. Destructors should never throw.

  7. Re-throw an exception.
    ✨ Show Answer
    catch (...) { log("oops"); throw; }
  8. Why does RAII make exception safety easier?
    ✨ Show Answer

    Cleanup is automatic via destructors during stack unwinding. You don't need try/finally — the destructor handles it.

  9. Catch order — base or derived first?
    ✨ Show Answer

    Derived first. Catches are tried top-to-bottom; if you catch std::exception& first, derived classes never reach their handlers.

  10. When is exception use a code smell?
    ✨ Show Answer

    For control flow over routine cases (e.g. "is this number even? throw if odd"). Exceptions are for exceptional cases.

  11. What is std::expected?
    ✨ Show Answer

    C++23 type holding either a value or an error. A type-safe alternative to throwing for expected failures.

  12. Catch invalid_argument from std::stoi.
    ✨ Show Answer
    try { int n = std::stoi("abc"); }
    catch (const std::invalid_argument& e) { /* ... */ }

Summary

Use exceptions for exceptional situations. Catch by const T&. Mark non-throwing functions noexcept. RAII + stack unwinding makes cleanup automatic. For routine errors, prefer std::optional or std::expected.

Next Module → C++17: optional, variant, structured bindings.