The STL — Iterators & Algorithms
cpp2-2's containers gave C++ real, standard data structures. This chapter is what makes them interchangeable: one std::sort, working identically across every container that offers iterators.
What an Iterator Is
A generalized pointer-like object. begin() points at the first element; end() points one past the last — never the last element itself, the "half-open range" convention [begin, end). Dereferencing (*it) gives the element; ++it advances.
Iterating With Iterators
cpp1-2's own range-based for (auto x : container) is genuinely sugar for exactly this iterator pattern, generated automatically underneath.
Why Iterators Exist — Generic Algorithms Over Any Container
The real payoff: std::sort/std::find/and friends don't know or care whether they're operating on a vector, a list, or a raw array — they only need begin()/end() iterators satisfying certain requirements. This is cpp2-1's templates applied one level up, at the algorithm level rather than the container level — std::sort is itself a function template.
std::sort
Sorts a range in place. c3-2's own hand-built structures never included a general sorting algorithm at all — writing one in C means implementing the actual algorithm by hand, every time.
std::find
A linear search returning an iterator to the found element, or end() if not found — the end()-as-sentinel pattern is idiomatic and used constantly across the STL.
Iterator Invalidation, Revisited
cpp2-2's own warn-box flagged reallocation invalidating iterators — with iterators now properly introduced, the fuller picture: erasing or inserting into a vector can invalidate iterators at or after the modification point too, not just growth-triggered reallocation.
| Concept | C (c3-2) | C++ STL |
|---|---|---|
| Traversal | hand-written loop, container-specific | iterators — the same syntax across any container |
| Sorting | implement the algorithm by hand | std::sort — one call, any container |
| Searching | hand-written traversal loop | std::find — returns an iterator, end() as "not found" |
std::sort/std::find and the rest of the STL's algorithm library are genuinely less error-prone than a hand-written loop, and usually at least as fast — real implementations are heavily optimized.
begin()/end(), or one that's already been invalidated, compiles cleanly and is undefined behavior at runtime — the type system doesn't tie an iterator to "the container it's still safely valid for," the way Rust's borrow checker would.
Coding Challenges
Create a std::vector
Use std::find to search a std::vector
Explain why the range-based for loop (for (auto x : container)) is described as "sugar" over the explicit iterator loop, and rewrite one range-based for loop yourself as its equivalent explicit iterator-based form.
📄 View solutionChapter 3 Quick Reference
begin()/end()— the half-open range[begin, end);end()points one past the last element- Range-based
foris sugar over the exact same iterator pattern, generated automatically - Algorithms like
std::sort/std::findwork identically across any container offering iterators — templates, one level up std::findreturnsend()as its "not found" sentinel — checkit != container.end()- Erasing/inserting/reallocating can invalidate existing iterators — using one afterward is undefined behavior, uncaught by the compiler
- Next chapter: smart pointers — unique_ptr and shared_ptr, a modern RAII alternative to raw malloc/free