Skip to main content

Exception Safety Guarantees

intermediate25 min readLesson 119 of 204

Basic, strong, noexcept; copy-and-swap; and why destructors must never throw.

Exception safety is a guarantee a function makes about its state when an exception flies through it. Three useful levels:

  • basic: invariants hold; nothing leaks; the object is destructible — but the value may be anything valid.
  • strong: the call either completes or has no effect (commit/rollback).
  • noexcept: never throws; moves and destructors should be here.

The canonical strong-guarantee idiom is copy-and-swap: do the risky work on a copy, then commit with non-throwing moves.

Config& operator=(const Config& other) {
    Config tmp{other};      // may throw — *this untouched
    std::swap(data_, tmp.data_);  // no-throw commit
    return *this;
}

Where exceptions fly from matters: between new and delete, a throw leaks; RAII (Module 8) closes that window by tying release to scope. Destructors must be noexcept — a throw inside unwinding calls std::terminate. This is why std::vector::erase with move-only types demands move constructors marked noexcept: reallocation would otherwise use the copying path.