Control Flow
For Loops
Traditional and range-based for loops
Interview: Essential for iteration
For Loops
The for loop is the workhorse of iteration in C++. It packs initialization, condition checking, and increment into a single compact line. C++11's range-based for loop further simplifies iteration over containers by eliminating manual index management.
Traditional For Loop
The traditional for loop has three components: init; condition; update. Any or all of these can be omitted (creating infinite loops or custom control flows).
Range-Based For (C++11)
Range-based for iterates over any container that provides begin() and end() iterators. Using auto& avoids copies for non-trivial types. Using const auto& for read-only access.
Index-Based vs Range-Based Trade-offs
Use index-based when you need the index itself (e.g., for comparing adjacent elements or bidirectional traversal). Use range-based for readability and safety when you only need element values.
Interview Corner
Q: What is the difference between for(auto x : v) and for(auto& x : v)?
A: auto x creates a copy of each element — modifications don't affect the container and copying is expensive for large objects. auto& x creates a reference to the actual element — modifications affect the container and no copy is made. Use const auto& for efficient read-only access.
Q: Why should you avoid calling size() in a loop condition for a container?
A: While most STL containers have O(1) size(), it's still a function call evaluated every iteration. More critically, comparing a signed int index against an unsigned size_t result can trigger implicit signed/unsigned comparison warnings and potential bugs. Cache the size: const auto n = v.size();
Common Pitfalls
- Off-by-one errors: Using
i <= sizeinstead ofi < sizeleads to out-of-bounds access. - Modifying container in range-based for: Adding/removing elements while iterating with a range-based for invalidates iterators and causes undefined behavior.
Best Practices
- Prefer range-based for loops for containers when index is not needed — they are safer and more expressive.
- Use
std::size_torptrdiff_tfor loop indices over containers to avoid signed/unsigned mismatch. - Consider standard algorithms like
std::for_eachorstd::transformfor more expressive and parallelizable iteration patterns.