Range-Based for Loop
Basic Syntax
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numbers = {10, 20, 30, 40};
for (int n : numbers) {
cout << n << " ";
}
cout << endl;
// Output: 10 20 30 40
return 0;
}Compare this to the traditional index-based loop it replaces:
// The old way - works, but more room for off-by-one mistakes
for (size_t i = 0; i < numbers.size(); i++) {
cout << numbers[i] << " ";
}The range-based version is shorter, cannot go out of bounds, and works identically across arrays, std::vector, std::string, std::map, and any other type that exposes begin()/end().
auto vs auto&: Copies vs References
for (auto x : container) copies each element into x. For small types like int this is harmless, but for larger objects (a std::string, a custom class, a std::vector of vectors) that copy is wasted work on every single iteration.vector<string> names = {"Alice", "Bob", "Charlotte"};
// Copies each string - wasteful for large strings, and mutations
// to 'name' do NOT affect the vector.
for (auto name : names) {
name += "!"; // only modifies the local copy
}
// No copy - 'name' is a reference to the actual element.
// Mutations here DO affect the vector.
for (auto& name : names) {
name += "!";
}
cout << names[0] << endl; // Output: Alice!auto instead of auto& in a range-based for loop silently copies every element. For large or expensive-to-copy types, this can quietly make a loop far slower than it needs to be, and it also means changes inside the loop body never reach the original container.const auto& for Read-Only Iteration
const auto&. It avoids the copy of auto while also preventing accidental modification, which is the safest and most common form you'll see in idiomatic C++ code.vector<string> names = {"Alice", "Bob", "Charlotte"};
for (const auto& name : names) {
cout << name << " has " << name.size() << " characters" << endl;
// name += "!"; // would not compile - name is const
}Form | Copies element? | Can modify original? | Typical use |
|---|---|---|---|
auto x | Yes | No | Small, cheap-to-copy types (int, char) |
auto& x | No | Yes | Need to modify elements in place |
const auto& x | No | No | Read-only access, especially to large objects |
Iterating a C-Style Array
Range-based for also works directly on fixed-size C-style arrays, because the compiler knows their size at compile time.
#include <iostream>
using namespace std;
int main() {
int scores[] = {85, 90, 78, 92};
for (int score : scores) {
cout << score << " ";
}
cout << endl;
// Output: 85 90 78 92
return 0;
}int arr[].Key Points
Range-based for (C++11) iterates every element of a container or array without manual indexing.
Plain auto copies each element - use auto& to modify elements or avoid copies of large types.
const auto& is the idiomatic choice for read-only iteration over non-trivial element types.
Works on arrays, std::vector, std::string, std::map, and any type with begin()/end().
Cannot be used on a pointer that has decayed from an array - the size must be known.