5.2.21C++ Programming

Iterators — input, output, forward, bidirectional, random access, contiguous

2,131 words10 min readdifficulty · medium

WHY do iterators exist at all?


The six categories (the WHAT)

Figure — Iterators — input, output, forward, bidirectional, random access, contiguous

HOW the compiler uses categories (tag dispatch)

template<class It>
void advance_impl(It& it, int n, std::random_access_iterator_tag) {
    it += n;                       // O(1) — only legal here
}
template<class It>
void advance_impl(It& it, int n, std::bidirectional_iterator_tag) {
    if (n >= 0) while (n--) ++it;  // O(n)
    else        while (n++) --it;
}
template<class It>
void advance_impl(It& it, int n, std::input_iterator_tag) {
    while (n--) ++it;              // O(n), forward only
}
template<class It>
void advance(It& it, int n) {
    advance_impl(it, n,
        typename std::iterator_traits<It>::iterator_category{});
}

Why this step? The empty tag object's type selects the overload at compile time — zero runtime cost, yet each container gets its optimal algorithm. This is the whole point of the hierarchy.


Worked examples


Common mistakes (Steel-man + fix)


Active recall

What is an iterator, in one phrase?
A generalized pointer giving uniform traversal over a container.
List the six iterator categories in refinement order.
Input/Output → Forward → Bidirectional → RandomAccess → Contiguous.
Which operation does Bidirectional add over Forward?
Backward stepping --it.
Which operations does RandomAccess add over Bidirectional?
it+n, it-n, it[n], it2-it1, ordering </>, all in O(1).
What extra guarantee does Contiguous add over RandomAccess?
Elements occupy one contiguous memory block: &*(it+n) == &*it + n.
What container has only bidirectional iterators, not random access?
std::list (also set, map).
Why is std::deque random-access but NOT contiguous?
Its memory is split into separate fixed-size chunks, so addresses aren't linear.
What does "single-pass" mean and which categories are single-pass?
Each element can be visited once; old positions become invalid. Input and Output iterators.
How does std::advance get O(1) for vectors and O(n) for lists with one name?
Tag dispatch on iterator_traits::iterator_category chooses an overload at compile time.
Example of an input iterator? An output iterator?
istream_iterator; ostream_iterator / back_insert_iterator.
Why does std::sort not work on std::list?
sort needs random-access iterators; list's are bidirectional — use list::sort() instead.
What category does forward add over input?
Multi-pass: you can copy an iterator and re-traverse.
Recall Feynman: explain to a 12-year-old

Imagine different toy boxes. A scroll of paper you can only read once as it unrolls — that's an input iterator. A stamp that only prints, never reads — that's output. A train on a one-way track that you can ride again from the start is forward. A train that can also reverse is bidirectional. A teleporter that jumps straight to seat #50 is random access. And if all the seats are bolted in one straight row with no gaps, that's contiguous. The fancier the toy, the more it can do — and the STL picks the cheapest trick each toy allows.


Connections

  • Pointers and pointer arithmetic — iterators generalize these.
  • STL Containers — vector, list, deque, map — each exposes a specific iterator category.
  • STL Algorithms — sort, find, copy — written against iterator categories.
  • Templates and Tag Dispatch — the compile-time mechanism behind advance/distance.
  • iterator_traits and type introspection — how the category tag is read.
  • Ranges library (C++20) — modern layer built atop iterator concepts.

Concept Map

solves

collapses to

classified by

form

refined by

refined by

adds --it

adds it+n O 1

adds contiguous storage

starts at

guarantees

Iterator = generalized pointer

M x N glue problem

M + N via common interface

Iterator categories

Refinement chain

Input read-only single-pass

Forward multi-pass

Output write-only single-pass

Bidirectional

Random Access

Contiguous

Elements in one memory block

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Socho iterator ek "smart pointer" hai jo kisi bhi container — vector, list, set, stream — ke upar same tareeke se chalne deta hai. Iska sabse bada faayda: STL algorithms (jaise sort, find, copy) ko ek hi baar likho, aur har container pe chal jaate hain, kyunki sab container iterators expose karte hain. Yahi decoupling C++ ko itna powerful banata hai.

Ab har container same speed se sab kuch nahi kar sakta, isliye iterators ki categories hoti hain. Sabse kamzor Input (sirf padho, ek baar) aur Output (sirf likho, ek baar). Uske upar Forward — dobara ghoom sakte ho. Phir Bidirectional — peeche bhi ja sakte ho (--it), jaise list aur set. Phir Random Access — seedha 50th element pe jump, it+n, O(1) mein, jaise vector aur deque. Aur sabse top Contiguous — elements ek hi continuous memory block mein, isliye &v[0] ko C function ko de sakte ho; ye sirf vector, array, string deti hain.

Important trap: deque random-access hai par contiguous nahi, kyunki uska data alag-alag chunks mein hota hai. Aur list ko std::sort se sort nahi kar sakte kyunki uske iterators sirf bidirectional hain — uske liye list.sort() use karo. std::advance ek hi naam se vector ke liye O(1) aur list ke liye O(n) kaise karta hai? Compile-time pe tag dispatch se — iterator ka category tag dekh kar sahi version chun leta hai. Yahi poori hierarchy ka asli maqsad hai: har container ko uska sabse fast algorithm mil jaaye.

Go deeper — visual, from zero

Test yourself — C++ Programming

Connections