Exception safety — basic, strong, no-throw guarantees
WHY do we even need this?
C++ exceptions can fire from almost anywhere: new throws std::bad_alloc, a copy constructor of a contained type can throw, a comparator can throw. The moment an exception propagates, the stack unwinds — destructors of local objects run, but the half-finished operation stops dead.
WHAT are the three guarantees?
There is implicitly a fourth, the worst case — no guarantee: leaks, corruption, undefined behaviour. We never want this.

HOW do we achieve each level?
Basic guarantee — use RAII
void basic_ok() {
auto p = std::make_unique<Widget>(); // owns memory
p->mutate(); // may throw
risky(); // may throw
// if either throws, ~unique_ptr frees the Widget. No leak.
} // object valid & destructible: BASIC guaranteeWhy this step? unique_ptr's destructor runs during unwinding, so no delete is skipped.
Strong guarantee — copy-and-swap
class Buffer {
int* data; std::size_t n;
public:
void append(const int* src, std::size_t k) { // STRONG
Buffer tmp(*this); // 1. copy (may throw — original safe)
tmp.grow_and_copy(src, k); // 2. do risky work on tmp (may throw)
swap(*this, tmp); // 3. noexcept commit
} // ~tmp frees old data
friend void swap(Buffer& a, Buffer& b) noexcept {
std::swap(a.data, b.data);
std::swap(a.n, b.n);
}
};Why this step? Steps 1 and 2 may throw, but they touch only tmp. If they throw, *this is exactly as before → no effect. Step 3 cannot throw → the commit is atomic.
No-throw guarantee — noexcept operations
void release(Resource* r) noexcept { /* free handles, never throws */ }A subtle but crucial point: move and the strong guarantee
Worked Examples
Recall Feynman: explain to a 12-year-old
Imagine you're repainting a room. Basic: if you get interrupted, the room is still a usable room — nothing's on fire — but it might be half blue, half white. Strong: you paint a spare wall panel first; only when it's perfectly done do you instantly snap it over the old wall. If you get interrupted, the old wall is still there, untouched — like you never started. No-throw: the job is so simple (flipping a light switch) it can never go wrong. The trick for "strong" is: do all the messy work on a copy, then swap it in at the last safe second.
Active Recall
What are the three exception-safety guarantees, weakest to strongest?
noexcept).What does the basic guarantee promise on a thrown exception?
What does the strong guarantee promise?
Which idiom achieves the strong guarantee and how?
Why must swap, destructors, and moves be noexcept for strong safety?
What technique gives the basic guarantee almost for free?
What happens if a noexcept function throws?
Why does std::vector copy rather than move during reallocation for some types?
Why does copy-and-swap assignment handle self-assignment automatically?
Strength ordering of the guarantees?
Connections
- RAII and resource management
- Smart pointers — unique_ptr, shared_ptr
- Copy-and-swap idiom
- Move semantics and noexcept
- std::vector reallocation strategy
- noexcept specifier and std::terminate
- Stack unwinding and destructors
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, exception safety ka matlab hai: agar tumhare function ke beech mein koi exception throw ho jaye (jaise new fail ho gaya, ya copy constructor ne throw kar diya), to tumhara program kis state mein chhoot jaata hai? Iske teen level hain. Basic guarantee ka matlab — koi memory leak nahi hogi aur object usable rahega, par values thodi half-baked ho sakti hain. Strong guarantee matlab "all-or-nothing": ya to pura kaam ho jaye, ya bilkul aisa lage jaise tumne shuru hi nahi kiya (rollback). No-throw matlab function kabhi throw karega hi nahi — yeh noexcept se mark karte hain.
Basic guarantee almost free milti hai agar tum RAII use karo — yaani har resource ek stack object (jaise unique_ptr) ke paas ho, to stack unwind hone par destructor apne aap cleanup kar dega. Leak ka chance hi nahi. Strong guarantee ke liye famous trick hai copy-and-swap: pehle saara risky kaam ek copy (tmp) par karo, aur jab copy poori ready ho jaaye, tab ek noexcept swap se use original mein daal do. Agar beech mein kuch throw hua to sirf tmp kharab hua, original safe — isliye "no effect".
Ek important baat: swap, destructors, aur move operations ko noexcept rakhna zaroori hai, warna commit step hi throw kar gaya to tum recover nahi kar paoge. Isi wajah se std::vector reallocation ke time, agar tumhare type ka move noexcept nahi hai, to woh move ki jagah copy karta hai (slow par safe). Aur dhyaan rakhna — noexcept tabhi lagao jab sach mein guarantee de sako, kyunki jhoot bol diya aur function throw kar gaya to seedha std::terminate() — program turant mar jaayega.