Namespaces
Variants
Views
Actions

intro/range for

From cppreference.com

[edit] The range-based for statement

The range-based for statement is a simpler and safer way to loop over the contents of a container or array.

It looks like this:

for (/* variable declaration */ : /* container or array */) {
    // statements
}

Which, for a container, expands to:

for (auto p = container.begin(); p != container.end(); ++p) {
    /* variable declaration */ = *p;
    // statements
}

For an array it expands to:

for (int n = 0; n != sizeof(array); ++n) {
    /* variable declaration */ = array[n];
    // statements
}

Normally you would use a variable declaration with auto, or possibly const auto&:

for (auto item : items) {
    // statements
}

If you don't use auto, the values in the container or array must be convertible to whatever type you use.

For example:

#include <iostream>
#include <string>
#include <vector>
 
int main()
{
    std::vector<std::string> doctors = { "Strange", "Octopus", "Who" };
 
    // You could use "std::string" instead of "auto"
    for (auto const& doc : doctors) {
        std::cout << "Paging Dr. " << doc << '\n';
    }
}

Output:

Paging Dr. Strange
Paging Dr. Octopus
Paging Dr. Who

If you use a non-const reference, you can change the values in the container or array within the loop:

For example:

#include <iostream>
 
int main()
{
    int numbers[] = { 1, 2, 3, 4 };
 
    // Print numbers
    for (auto n : numbers)
        std::cout << n << ' ';
 
    // Double each number
    for (auto& n : numbers)
        n *= 2;
 
    std::cout << '\n';
 
    // Print numbers
    for (auto n : numbers)
        std::cout << n << ' ';
}

Output:

1 2 3 4 
2 4 6 8

The range-based for statement is not only easier to write, it is safer. You cannot accidently go past the end of a container or array, or make other mistakes like this:

std::vector<int> c1 = { 1, 2, 3 };
std::vector<int> c2 = { 4, 5, 6 };
 
// Mixing the begin/end from c1 and c2 by accident!
// This causes undefined behaviour!
for (auto p = c1.begin(); p != c2.end(); ++p) {
    std::cout << *p << '\n';
}

On the other hand, the range-based for statement is more limited. You can't start half-way through the sequence, and you can't advance by more than one item at a time. You can keep track of where you are in the sequence, but it requires an extra variable. (And of course, you can always end before the end of the sequence with a break statement.)