Iterators in C++ STL
In this lesson: What iterators are in C++ STL — begin(), end(), types and loops — with examples and output. In Hindi & English.
What is an iterator?
An iterator is an object that points to an element in a container and knows how to move to the next one. It behaves like a pointer:
*it— the element it points to++it— move to the next elementit == other— are they at the same position?
Iterators are the glue of the STL: containers hand out iterators, and algorithms like sort, find and reverse work on any pair of iterators. That is why the same algorithm works on a vector, a list or a deque.
begin() and end()
Every container has:
begin()— iterator to the first elementend()— iterator one past the last element
vector: [ 78 | 91 | 66 | 84 ]
^ ^
begin() end() (past the last element)The half-open range [begin, end) makes loops simple — stop when you reach end() — and an empty container has begin() == end().
Looping with an iterator
#include <iostream>
#include <vector>
int main() {
std::vector<int> marks = {78, 91, 66, 84};
// explicit iterator type
for (std::vector<int>::iterator it = marks.begin(); it != marks.end(); ++it) {
*it += 2; // grace marks: modifies the element
}
// same thing with auto (C++11)
for (auto it = marks.begin(); it != marks.end(); ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
// range-based for uses iterators behind the scenes
for (int m : marks) std::cout << m << " ";
std::cout << "\n";
return 0;
}A range-based for is the simplest choice when you just need every element. Use explicit iterators when you need the position, want to erase while looping, or pass a range to an algorithm.
The five iterator categories
| Category | Can do | Provided by |
|---|---|---|
| Input | Read once, move forward (*it, ++it) | istream_iterator |
| Output | Write once, move forward | ostream_iterator, back_inserter |
| Forward | Read/write, move forward many times | forward_list, unordered_map |
| Bidirectional | Forward + move back (--it) | list, set, map |
| Random-access | Bidirectional + jump (it + 3, it[2], it2 - it1, <) | vector, deque, array, plain pointers |
Each category includes the abilities of the ones above it. An algorithm states the minimum it needs — std::sort requires random-access iterators, which is why list has its own list.sort().
const and reverse iterators
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
for (auto it = v.cbegin(); it != v.cend(); ++it) { // const_iterator
std::cout << *it << " "; // *it = 9; would not compile
}
std::cout << "\n";
for (auto it = v.rbegin(); it != v.rend(); ++it) { // reverse_iterator
std::cout << *it << " ";
}
std::cout << "\n";
return 0;
}Use cbegin()/cend() when you only read, so the compiler stops accidental changes. rbegin()/rend() walk backwards.
Useful iterator functions
| Function | Meaning |
|---|---|
std::next(it, n) | Iterator n steps ahead (default 1) |
std::prev(it, n) | Iterator n steps back |
std::advance(it, n) | Move it itself by n |
std::distance(a, b) | Number of steps from a to b |
These work for every category, even list, where it + 3 is not allowed.
std::vector<int> v = {10, 20, 30, 40};
auto it = std::find(v.begin(), v.end(), 30);
std::cout << "index = " << std::distance(v.begin(), it) << "\n"; // 2
std::cout << "last = " << *std::prev(v.end()) << "\n"; // 40Iterators over a map
A map iterator points to a pair: ->first is the key and ->second is the value.
std::map<std::string, int> marks = {{"Aman", 78}, {"Priya", 91}};
for (auto it = marks.begin(); it != marks.end(); ++it) {
std::cout << it->first << ": " << it->second << "\n";
}Iterator invalidation
Changing a container can make existing iterators invalid (dangling):
| Container | Operation | Iterators that become invalid |
|---|---|---|
vector | push_back, insert (with reallocation) | All |
vector | erase | At and after the erased element |
deque | Insert at either end | All iterators (references stay valid) |
list, set, map | erase | Only the erased element's iterator |
Safe way to erase while looping — use the iterator that erase returns:
std::vector<int> marks = {35, 20, 50, 12, 40};
for (auto it = marks.begin(); it != marks.end(); ) {
if (*it < 33) it = marks.erase(it); // erase returns the next valid iterator
else ++it;
}
// marks: 35 50 40(For vectors the idiomatic one-liner is std::erase_if(marks, [](int m){ return m < 33; }); in C++20.)
Common mistakes
- Dereferencing
end()or an iterator from an empty container. - Comparing iterators from two different containers.
- Using
it + 1on alistormapiterator — usestd::next(it). - Keeping an iterator after
push_backon a vector. - Writing
it++insideeraseloops incorrectly and skipping elements.
Fill a list<int> with 10 numbers. Using only iterators, print it forwards and backwards, find the first number greater than 50 with std::find_if, print its position with std::distance, and erase every even number safely.
Summary
- An iterator points to an element and moves through a container like a pointer.
begin()is the first element;end()is one past the last — never dereference it.- Categories: input, output, forward, bidirectional, random-access.
cbegin/cendfor read-only,rbegin/rendfor reverse.- Modifying a container can invalidate iterators; use the iterator returned by
erase.
Related: STL introduction, vector, algorithms, list and deque.
Frequently Asked Questions
What is an iterator in C++?
*it gives the element, ++it moves forward, and comparing with end() tells you when to stop. Algorithms such as sort and find take iterators to know which range to work on.What does end() return in C++?
end() returns an iterator to the position just after the last element, not to the last element itself. It marks where a range stops. Dereferencing end() is undefined behaviour; to reach the last element use std::prev(v.end()) or v.back().What are the types of iterators in C++?
vector and deque give random-access iterators (it + 5 works), list, set and map give bidirectional iterators (only ++ and --), and stream iterators are input or output iterators.What is iterator invalidation?
vector, push_back may reallocate memory and invalidate all iterators, and erase invalidates iterators at and after the erased position. Using an invalid iterator is undefined behaviour.