5.2.29 · Coding › C++ Programming
Intuition Ek-sentence idea
Jab ek function apna kaam adha karke throw karta hai, tab tumhara program kis state mein rehta hai? Exception safety ek contract hai jo batata hai ki ek thrown exception kitna nuksan kar sakta hai. Teen guarantees us contract ko rank karti hain — "kuch leak nahi, but values adhi-pakki ho sakti hain" se lekar "operation ya poora succeed karega ya aisa behave karega jaise chala hi nahi" tak.
C++ exceptions almost kahin se bhi fire ho sakti hain: new throws std::bad_alloc, kisi contained type ka copy constructor throw kar sakta hai, ek comparator throw kar sakta hai. Jaise hi exception propagate hoti hai, stack unwind hota hai — local objects ke destructors run karte hain, lekin adha-khatam operation wahi ruk jaata hai.
Soch lo tum ek vector mein insert kar rahe ho: tum nayi memory allocate karte ho, elements copy karna shuru karte ho, aur copy #3 throw karta hai. Ab tumhare paas hai: old array abhi bhi alive, new array adha-bhara, aur adha-adhoora operation. Agar tum yeh carelessly handle karo toh tumhe memory leaks , corrupted invariants , ya double-frees milenge. Exception safety woh discipline hai jo yeh hone se rokti hai.
Definition Exception-safety guarantees (Abrahams guarantees)
Basic guarantee : agar exception throw hoti hai, koi resources leak nahi hote aur saare objects valid (usable, destructible) lekin unspecified state mein rehte hain. Invariants hold karte hain; exact values badal sakti hain.
Strong guarantee : agar exception throw hoti hai, operation ka koi effect nahi hota — state exactly waisi hi rollback ho jaati hai jaisi call se pehle thi (commit-or-rollback , transactional).
No-throw (nofail) guarantee : operation kabhi throw nahi karta ; yeh hamesha succeed karta hai. noexcept ke saath mark kiya jaata hai.
Implicitly ek chautha bhi hai, sabse bura case — no guarantee : leaks, corruption, undefined behaviour. Hum yeh kabhi nahi chahte.
Intuition RAII "basic" guarantee free mein kyun deta hai
Agar har resource (memory, file, lock) ek stack object ke paas owned hai jiska destructor use release karta hai, toh stack unwinding automatically clean up kar deta hai. Tum leak nahi kar sakte, kyunki cleanup scope exit se tied hai, function ke end tak pahunchne se nahi.
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 guarantee
Yeh step kyun? unique_ptr ka destructor unwinding ke dauran run karta hai, toh koi delete skip nahi hota.
Intuition Copy-and-swap "strong" kyun deta hai
Saara throwing work ek copy par karo. Sirf jab copy poori tarah ban jaaye, tab use jagah par swap karo. Pointers/handles ka swap noexcept hota hai. Toh original untouched rehta hai bilkul last, non-throwing instant tak — ya toh tum cleanly commit karte ho ya original intact rakh ke bail out karte ho.
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);
}
};
Yeh step kyun? Steps 1 aur 2 throw kar sakte hain, lekin woh sirf tmp ko touch karte hain. Agar woh throw karein, toh *this exactly pehle jaisa hai → koi effect nahi . Step 3 throw nahi kar sakta → commit atomic hai.
Intuition Destructors aur swaps throw kyun nahi karne chahiye
Strong-guarantee trick rely karti hai swap ke no-throw hone par. Agar swap mid-commit throw kare, tum ek half-swapped, unrecoverable state mein stuck ho jaate. Isliye swap, destructors, aur move operations noexcept honi chahiye.
void release ( Resource * r ) noexcept { /* free handles, never throws */ }
Common mistake Steel-man: "Main safety ke liye sab kuch
noexcept mark kar dunga."
Kyun sahi lagta hai: stronger guarantee = better, hai na? The trap: agar ek noexcept function actually throw kare, toh runtime std::terminate() call karta hai — tumhara program instantly mar jaata hai, koi unwinding nahi. noexcept sirf tab mark karo jab tum truly guarantee kar sako koi throw nahi (swaps, moves, deallocation). Compiler se jhooth bolna fatal hai.
std::vector kyun care karta hai ki tumhara move throw karta hai ya nahi
Jab ek vector reallocate karta hai, use elements nayi buffer mein transfer karne hote hain. Agar woh unhe move kare aur ek move halfway throw kare, purana buffer pehle se adha khaali ho chuka hai → strong guarantee khuch jaati hai . Toh standard library sirf tabhi move karti hai jab type ka move constructor noexcept ho; warna woh copy karti hai (slower, lekin copy source ko intact chodti hai → strong guarantee preserved). Yahi famous std::move_if_noexcept rule hai.
Worked example Example 2 — Strong tak upgrade karo
void f_strong ( std :: vector < int > & v , int x ) {
std ::vector <int> tmp = v; // copy (may throw → v safe)
tmp. push_back (x); // work on copy
log_to_file (x); // may throw → v still safe
v. swap (tmp); // noexcept commit
}
Yeh step kyun? Har throwing action tmp par hota hai. Visible state v sirf swap par change hoti hai, jo throw nahi kar sakta → strong .
Worked example Example 3 — Copy-and-swap ke through assignment
Buffer & operator = ( Buffer rhs ) { // rhs is a copy (pass-by-value)
swap ( * this , rhs); // noexcept
return * this ; // ~rhs frees old data
}
Yeh step kyun? Copy (potentially throwing) body shuru hone se pehle banti hai, argument passing ke through. Andar, sirf ek no-throw swap run hota hai → strong, aur self-assignment-safe bhi free mein.
Recall Feynman: ek 12-saal ke bacche ko samjhao
Soch lo tum ek kamra repaint kar rahe ho. Basic: agar tum beech mein ruk jaate ho, kamra abhi bhi usable hai — kuch jal nahi raha — lekin adha blue, adha white ho sakta hai. Strong: tum pehle ek spare wall panel paint karte ho; sirf jab woh perfectly ban jaata hai tab tum use instantly purani wall par snap kar dete ho. Agar tum beech mein ruk jaate ho, purani wall abhi bhi wahin hai, untouched — jaise tune start hi nahi kiya. No-throw: kaam itna simple hai (ek light switch flip karna) ki yeh kabhi galat ho hi nahi sakta. "Strong" ka trick hai: saara messy kaam ek copy par karo, phir use last safe second mein swap karo.
Mnemonic Ladder yaad karo
"Basic Suits No One Perfectly" → B asic (valid, no leak), S trong (no effect / rollback), N o-throw (noexcept). Aur tool ladder: RAII → copy-and-swap → noexcept .
Basic guarantee kya promise karta hai jo "no guarantee" nahi karta?
swap ki kaun si single property copy-and-swap ko strong guarantee deti hai?
std::vector kabhi kabhi reallocation ke dauran move ki jagah copy kyun karta hai?
Agar ek noexcept function actually throw kare toh kya hota hai?
Teen exception-safety guarantees kaun si hain, weakest se strongest? Basic (valid state, no leaks), Strong (commit-or-rollback / throw par koi effect nahi), No-throw (kabhi throw nahi karta, noexcept).
Basic guarantee thrown exception par kya promise karta hai? Koi resource leaks nahi aur saare objects ek valid, destructible lekin unspecified state mein rehte hain; invariants hold karte hain.
Strong guarantee kya promise karta hai? Commit-or-rollback: agar throw kare, toh operation ka koi effect nahi hota — state exactly call se pehle jaisi hoti hai.
Kaun sa idiom strong guarantee achieve karta hai aur kaise? Copy-and-swap: throwing work ek copy par karo, phir use noexcept swap se swap karo taaki commit throw na kar sake.
Swap, destructors, aur moves noexcept kyun hone chahiye strong safety ke liye? Copy-and-swap mein commit step throw nahi kar sakta; agar karta, toh tum ek unrecoverable half-done state mein stuck ho jaate.
Kaun si technique basic guarantee almost free mein deti hai? RAII — stack objects ke paas owned resources stack unwinding ke dauran destructors ke zariye release hote hain.
Agar ek noexcept function throw kare toh kya hota hai? std::terminate() immediately call hota hai; aage koi stack unwinding nahi hoti.
std::vector kuch types ke liye reallocation ke dauran move ki jagah copy kyun karta hai?Agar move constructor noexcept nahi hai, toh mid-move throw source ko gut kar dega aur strong guarantee tod dega, isliye woh copy karta hai (std::move_if_noexcept).
Copy-and-swap assignment self-assignment automatically kyun handle karta hai? Right-hand side copy ki jaati hai (by value) swap se pehle, toh kisi object ko khud se assign karna sirf copy karta hai phir harmlessly swap karta hai.
Guarantees ki strength ordering? no guarantee < basic < strong < no-throw; har stronger level saare weaker wale imply karta hai.
Exception thrown mid-operation
Leaks, corruption, double-free
Exception safety contract