Worked examples — Iterators — input, output, forward, bidirectional, random access, contiguous
5.2.21 · D3· Coding › C++ Programming › Iterators — input, output, forward, bidirectional, random ac
Kuch bhi shuru karne se pehle, do words jo hum baar baar use karte hain:
Scenario matrix
Har iterator exercise inhi cells mein se ek hoti hai. Hum har cell ko ek labelled example se cover karenge. "Negative move" cell mein hume aisa iterator chahiye jo peeche step kar sake — matlab bidirectional, random access, ya contiguous category (woh teen jo --it define karte hain).
| Cell | Kya special hai | Degenerate / limit uske andar |
|---|---|---|
| A. Positive move, random access | it += n, ek jump |
n = 0 (koi move nahi) |
| B. Positive move, bidirectional | loop ++it karna padega, |
exactly end() pe pahunchna |
| C. Negative move | --it, sirf bidirectional / random access / contiguous pe legal |
begin() se pehle step nahi karna |
| D. Single-pass input | ek baar padho, wapas nahi ja sakte | copy-then-advance dusre ko invalidate karta hai |
| E. Output only | write-only, koi == nahi, koi end nahi |
kitna likhna hai yeh jaanna |
| F. Contiguous vs merely random | &*(it+n) == &*it + n |
deque isse tod deta hai |
| G. Empty / one-element range | begin() == end() |
distance ; --end() illegal |
| H. Word problem | minimum category pick karo | over-constraining ek design bug hai |
| I. Exam twist | kaun si line compile nahi hogi aur kyun | tag-dispatch reasoning |
Example 1 — Cell A: vector pe positive jump (aur n = 0 limit)
v.begin()index 0 ko point karta hai, value10. Yeh step kyun? Har walk ko ek known starting anchor chahiye;begin()by definition index 0 hai.advance(it, 3)ek random-access iterator peit += 3ban jaata hai — index 3 tak ek single jump. Yeh step kyun? Parent ka tag dispatchvectorke liyerandom_accessoverload pick karta hai. Kyunki vector ek flat block hai, address arithmetic index 3 ko bina index 1 ya 2 touch kiye dhundh leta hai — isliye cost constant rehti hai () chahe vector kitna bhi bada ho. Index , value40. Toha = 40.advance(it, 0)zero steps move karta hai — loop body kabhi nahi chalta /it += 0ek no-op hai. Yeh step kyun? Degeneraten = 0ko iterator ko exactly wahan rakhna chahiye jahan tha;b = *it = 40.
Verify: index arithmetic ;
v[3] = 40, toha == b == 40.begin()se finalittak ki distance3hai. ✓
Example 2 — Cell B + G limit: list ko end() tak exactly walk karna
listiterators sirf bidirectional hain, tohadvancelooping overload pick karta hai:while(n--) ++it;. Yeh step kyun? Linked list ke paas koi contiguous block nahi hai, toh koi+=nahi; tumhe physically node by node hop karna padega — aur kyunki steps move karne ki cost separate hops hai, kaam ke saath badhta hai: yeh list ki (linear) reality hai.- Loop
n = 3ke liye chalta hai:++it3 baar execute hota hai, last element ke ek baad land karke. Yeh step kyun? Size 3 ke container mein valid positions hain aur sentinelend()"position 3" pe hai.begin()se 3 baar step karne se exactlyend()pe pahuncho. it == L.end()truehai. Yeh step kyun? Yeh limit case hai:end()legal stopping point hai. Yahan*itread karna undefined hoga, lekin compare karna theek hai.
Figure aise samjho: bottom row ke teen mint boxes real elements hain positions 0, 1, 2 pe jo 7, 8, 9 hold karte hain. Bilkul right ki taraf butter box, position 3 pe end() label ke saath, sentinel hai — notice karo uske andar koi value nahi hai, yeh tumhara visual reminder hai ki ise dereference karna illegal hai. Position 0 pe girne wali lavender arrow woh jagah hai jahan begin() start hota hai. Ab top pe teen curved coral arrows count karo: har ek ek ++ hai. Unhe left se right trace karo aur dekho teesri arrow squarely empty end() box pe land kari — yeh landing poora answer hai. Yeh dono dikhata hai ki exactly teen ++ calls chale (teen arrows) aur kyun atEnd true hai (last arrow sentinel pe pahunchti hai, uske past nahi).

Verify:
++calls ki numberLki size; distancebegin()→end()size ke barabar hai, tohatEnd == true. ✓
Example 3 — Cell C: bidirectional pe negative move, begin() guard karna
setbidirectional hai, toh negativenwhile(n++) --it;pick karta hai. Yeh step kyun? Sirf bidirectional-or-better iterators--define karte hain. Ekstd::setek balanced binary search tree mein store hota hai, aur--itin-order predecessor node pe jaata hai. Woh walk tree ke upar ya neeche ja sakta hai, toh iska worst-case cost tree height ke proportional hota hai, jo ek balanced tree ke liye hai — sasta, lekin not woh jo vector deta hai. (Ek full front-to-back traversal har node ko exactly ek baar visit karta hai, toh yeh kul total hai; baat yeh hai ki ek single--tree height se bounded hai, constant nahi.) Kisi bhi tarah--yahan legal hai, yahi Cell C ko chahiye.end()last element35ke ek past hai. Pehla--it35pe land karta hai. Yeh step kyun? Tumhe kabhiend()dereference nahi karna chahiye, lekin tum ise decrement kar sakte ho — pehla--real last element pe move karta hai.- Doosra
--it25pe land karta hai. Yeh step kyun? Sentinel se do backward steps:35→25. Tohval = 25. - Degenerate guard: hum room ke saath ruke. Agar humne
advance(it, -5)likhte ek 4-element set keend()se, toh humbegin()se pehle step karte — undefined behaviour. Yeh step kyun? Cell C ka chupaaya hua trap: backward moves range ko underflow nahi karne chahiye; standard koi safety net nahi deta.
Verify: sorted set
{5,15,25,35};end()se do steps peeche → element indexsize - 2 = 2pe → value25. ✓
Example 4 — Cell D: single-pass input, copy invalidate karta hai
istream_iteratorek input iterator hai: single-pass. Yeh step kyun? Yeh ek stream ka thin wrapper hai jo characters already consume kar chuka hai — koi rewind nahi hai, jo iske `iterator_category`input_iterator_taghone se match karta hai.*it100read karta hai lekin abhi remove nahi karta;first = 100. Yeh step kyun? Pehla token tab buffer mein aa gaya tha jab iterator construct hua tha.++itshared stream se agla token consume karta hai. Yeh step kyun? Donoitaurcopyek hi underlyingsspe hain. Kisi ek ko advance karna dono ke liye stream move karta hai — copies input iterators ke liye independent nahi hote.- Advance ke baad
*copysafe nahi hai use karna. Yeh step kyun? Standard ke input-iterator requirements (Cpp17InputIteratorrules, [input.iterators]) validity sirf single pass ke liye guarantee karte hain: jab tum input iterator ki kisi bhi copy ko increment karo, baaki saari copies invalidate ho jaati hain, aur invalidated iterator ko dereference karna undefined behaviour hai — matlab program ka koi defined meaning hi nahi hai (yeh200print kar sakta hai, garbage print kar sakta hai, ya crash ho sakta hai). Yeh unspecified behaviour se zyada strong hai, jahan tumhe kam se kam koi valid value milti ek known set mein se. Safe conclusion hai: copy ko advance karne ke baad kabhi mat padho. Sirf forward iterators is guarantee ko multi-pass tak upgrade karte hain, jahan copies independent hoti hain.
Verify: checkable facts hain
first == 100, aur category input (single-pass) hai, tohcopyke baare mein multi-pass reasoning invalid hai. ✓
Example 5 — Cell E: output-only, tumhe writes count karni hongi
back_inserterek pure output iterator hai. Yeh step kyun?*out = xka matlab haidst.push_back(x); koi==nahi, koi end sentinel nahi. Tum "kya main done hun?" nahi pooch sakte — tumhe count khud jaanna padega (yahan 4 loop items hain).- Har
*out = x; ++out;ek element append karta hai. Yeh step kyun? Output iterators exactly*it = vaur++itsupport karte hain;++ek formality hai (back-inserters ke liye no-op hai) jo algorithm ki shape uniform rakhti hai. - 4 writes ke baad,
dst = {1,2,3,4}, tohn = 4. Yeh step kyun? Likhi gayi count source items ki count ke barabar hai — ek maatra "length" information jo available hai.
Verify: ek empty vector mein 4 writes
dst.size() == 4aurdst == {1,2,3,4}dete hain. ✓
Example 6 — Cell F: contiguous apna promise rakhta hai, deque nahi rakhta
vectorcontiguous hai, toh iske elements ek block mein rehte hain: element ka addressbase + k * sizeof(double)hai. Yeh step kyun? Contiguity woh ek guarantee hai jo random access se upar hai — parent ki table row "contiguous storage guarantee" dekho.&*(v.begin()+2)v[2]ka address hai;&*v.begin() + 2base address plus 2 elements hai. Yeh step kyun? Hum "iterator walk karo phir address lo" vs "base address lo phir 2 add karo" compare kar rahe hain — contiguity kehti hai yeh identical hain. TohvecOK = true.- Ek
dequeit[2]mein support karta hai (random access) lekin element 2 ek alag chunk mein store ho sakta hai. Yeh step kyun? Random access pointer arithmetic ke liye necessary but not sufficient hai.dequepe address equality silently fail kar sakti hai, isliye tum&v[0](contiguous) to C API ko de sakte ho jo flat array expect kari ho lekin kabhi&deque[0]nahi — yeh fact pointer arithmetic se flow karta hai.
Figure aise samjho: dono rows ko box-for-box compare karo. Top lavender row vector hai. Iske char boxes v[0]..v[3] edge to edge hain bina gaps ke, aur unke neeche chhote grey labels base+0, base+1, base+2, base+3 likhte hain — perfectly linear. v[2] pe apni finger rakho aur uska label check karo: woh hai base+2, toh right side ka mint "✓" earned hai. Bottom row deque hai: do coral boxes (d[0], d[1]), phir ek labelled gap (visual cue ki ek naya memory chunk shuru hota hai), phir do butter boxes (d[2], d[3]). Ab d[2] pe apni finger rakho: woh gap ke across rehta hai, toh uska real address base+2 nahi hai — wahi tuti hui linearity hai jo coral "✗" warn karta hai. Dono rows mein ek hi difference — gap vs no gap — woh poora reason hai ki sirf contiguous storage base + n identity rakhta hai.

Verify: ek contiguous
doublearray ke liye,&a[2] == a + 2exactly pointer identity hai;vecOK == true. ✓
Example 7 — Cell G: empty aur single-element ranges
- Empty container ke liye
begin() == end()hota hai. Yeh step kyun? Koi jaghah point karne ki nahi hai, toh dono sentinels ek saath milte hain; equal iterators ke beech ki distance0hai. Tohd0 = 0. - Ek element ke liye,
end()index 0 ke ek step past hai. Yeh step kyun? Distance =begin()seend()tak++ki count = size =1. Tohd1 = 1. - Degenerate trap: empty vector pe,
--empty.end()undefined hai — land karne ke liye koi element nahi hai. Yeh step kyun? Limit case: tumend()ko tabhi decrement kar sakte ho jabsize >= 1ho. Yeh Cell G ka chupaaya hua edge hai jo har exam ko pasand hai.
Verify:
distance == sizeforward-or-better range ke liye, tohd0 == 0,d1 == 1. ✓
Example 8 — Cell H: word problem, minimum category pick karo
- List the operations jo tum actually use karte ho:
*it(read),++it,it != Last. Yeh step kyun? Sahi category used operations se decide hoti hai, habit se nahi — over-constraining valid containers ko reject karta hai. - Tum kabhi peeche nahi jaate, kabhi jump nahi karte, har element ek baar padhte ho. Yeh step kyun? Koi
--, koi+nnahi: bidirectional aur random access unnecessary hain. Single-pass read +!=exactly input iterator contract hai. - Minimum = input iterator; passes = 1. Yeh step kyun? Accepted set ko random-access se input tak widen karna
forward_list,istream, sab kuch work karne deta hai — yeh algorithm/iterator decoupling ka poora point hai. Teammate karandom_accessconstraint ek over-specification bug tha.
Verify: used operations = {read,
++,!=}; teeno provide karne wali least category input hai (multi-pass bhi required nahi), toh minimum category index = 1 (input), passes = 1. ✓
Example 9 — Cell I: exam twist, kaun si line fail hoti hai aur kyun
- Line X
a + 2use karta hai. Yeh step kyun? Iterators pe+operator sirf random-access (aur contiguous) iterators ke liye exist karta hai.listiterator bidirectional hai, toh yeh++/--define karta hai lekinoperator+nahi.a + 2ke liye koi valid overload nahi hai, toh compiler line X reject karta hai. Yahi failing line hai. - Line Y
std::advance(a, 2)theek compile hoti hai. Yeh step kyun?advancesabhi iterator categories ke liye tag dispatch ke zariye defined hai; bidirectional iterator ke liye yeh silently++ako do baar loop karne pe fall back karta hai (). Yeh kabhioperator+nahi maangta, toh yeh wahan succeed karta hai jahan line X nahi kar sakta tha — yeh exactly parent note kaadvanceworkaround hai. - Line Z
std::distance(L.begin(), a)bhi compile hoti hai. Yeh step kyun?distancebhi category pe dispatch karta hai aur bidirectional ke liye++steps count karta hai; ise koioperator-nahi chahiye. Toh Z bhi theek hai. - Line X delete karo aur run karo.
advance(a, 2)ke baad,aindex 2 pe baitha hai (value6), aurdistance(begin(), a)2 steps count karta hai. Yeh step kyun? Yeh intended answer confirm karta hai: sirf line X fail hoti hai, aur remove karne ke baad,gap = 2aur*a == 6.
Verify: illegal
+hatane ke baad,advance(a,2)ako index 2 pe rakhta hai, tohgap == 2aur*a == 6. ✓
Active recall
Recall Quick self-test
vector pe advance(it, 0) kya karta hai? ::: Kuch nahi — degenerate zero move iterator ko unchanged chhod deta hai.
{5,15,25,35} ke set::end() se do -- kaunsi value dete hain? ::: 25 (index size−2).
istream_iterator ki stale copy padhna kyun unsafe hai? ::: Input iterators single-pass hote hain; kisi bhi copy ko increment karna baaki sabko invalidate karta hai, aur invalidated iterator ko dereference karna undefined behaviour hai.
Empty container ke liye distance(begin(), end()) kitna hota hai? ::: 0, kyunki begin() == end() hota hai.
Ek range ek baar print karne ke liye minimum iterator category kaun si hai? ::: Input iterator.
std::list ke liye L.begin() + 2 kyun fail hota hai? ::: operator+ sirf random-access/contiguous ke liye exist karta hai; list iterators bidirectional hain, toh unke paas koi + nahi.
std::set pe single --it ka worst-case cost kya hai? ::: — balanced tree ki height se bounded, constant nahi.
deque it[n] ko O(1) mein support karta hai — kya &*(it+n) == &*it + n guaranteed hai? ::: Nahi; us address identity ke liye contiguous category chahiye, jo deque ke paas nahi hai.