Exceptions — a mechanism built on stack unwinding
C++ exceptions are not "Java/Python exceptions with different syntax". They are a mechanism inseparable from stack unwinding and RAII: the language guarantees resource release through destructors of locals on the path from throw to catch. Without RAII, unwinding still runs "through objects" — but resources themselves leak. With RAII, everything is released automatically.
C++ also gives you a wide design space: you can disable exceptions entirely (-fno-exceptions), express "expected" failures via std::optional/std::expected, and pick a safety guarantee per operation (nothrow / strong / basic). The traps are principled too: throwing from a destructor or noexcept function is an instant std::terminate; a move without noexcept disables vector optimizations; throw e; instead of throw; loses the dynamic type.
Topic map
- try/catch — basic syntax — how
try,catch,throware written; which errors must not be swallowed. - Throw by value, catch by reference — the canonical C++ rule.
- std::exception hierarchy — standard classes; deriving your own exceptions.
- Catch chain — handler order,
catch(...), polymorphic catching. - Stack unwinding — what exceptions do on the way out; what breaks unwinding.
- RAII — acquire in constructor — why exceptions without RAII are dangerous; the "no bare ownership" rule.
- noexcept — the "does not throw" contract — functional, not cosmetic; impacts
std::vector. - Exception safety guarantees — Sutter's levels (nothrow/strong/basic/none), copy-and-swap.
- Destructor safety — double-throw →
std::terminate; handling potentially-throwing cleanup. - Constructor exception safety — the destructor will not run; globals and
std::terminate. - Rethrow and std::exception_ptr — bare
throw;, propagation across threads. - Runtime errors — what the standard library throws and what it does not.
- Error alternatives —
optional,expected,error_code,-fno-exceptions. - Error handling strategy — where exceptions, where value-based; declaring the contract.
Common traps
| Mistake | Consequence |
|---|---|
Catch by value (catch (std::exception e)) | Slicing — derived type lost, virtual methods broken |
Empty catch(...) {} without throw; | Error silently swallowed, lost forever |
throw e; instead of throw; | Copied as the static type — derived class discarded |
Base type in catch above the specific type | The specific handler is dead code |
| Throwing from a destructor during unwinding | Immediate std::terminate |
Throwing from a noexcept function | Immediate std::terminate, no unwinding |
Move constructor without noexcept | std::vector copies instead of moving on realloc |
Raw new in init list or constructor body | Leak if a later step throws |
| Throwing from a global / static constructor | std::terminate — no surrounding try |
| Using exceptions as control flow on hot paths | An order of magnitude more expensive than branches |
try/catch around noexcept operations | Dead code; hides bugs |
Interview relevance
Exceptions are a topic where interviewers quickly tell shallow knowledge from real depth. Everyone knows try/catch syntax; the real questions start after.
What is actually being checked:
- The link between unwinding and RAII — why one without the other breaks.
- Safety guarantees (nothrow/strong/basic) and how strong is implemented via copy-and-swap.
- Why
noexceptis functional:std::vectorrealloc picks move only whennoexcept. - What triggers
std::terminate— three or four cases by heart. - Why
throw;is different fromthrow e;and how the first preserves the dynamic type. - When to choose
std::optional/std::expectedover exceptions.
Popular questions:
- Explain stack unwinding. What happens to locals?
- Which exception safety guarantees do you know? Implement strong guarantee for
operator=. - Why must move constructor be
noexcept? - What triggers
std::terminate()? Name at least three cases. - How do you pass an exception from a worker thread to the main thread?
- How is
throw;different fromthrow e;? - When are exceptions the wrong tool?
Common candidate mistake: treating exceptions as "the Java/Python thing with different syntax". In C++ they are inseparable from RAII and stack unwinding — answers without that connection stay shallow.