for
StatementThe new standard introduced a simpler for
statement that can be used to iterate through the elements of a container or other sequence. The syntactic form of the range for
statement is:
for (declaration : expression)
statement
expression must represent a sequence, such as a braced initializer list (§ 3.3.1, p. 98), an array (§ 3.5, p. 113), or an object of a type such as vector
or string
that has begin
and end
members that return iterators (§ 3.4, p. 106).
declaration defines a variable. It must be possible to convert each element of the sequence to the variable’s type (§ 4.11, p. 159). The easiest way to ensure that the
Exercise 5.15: Explain each of the following loops. Correct any problems you detect.
(a) for (int ix = 0; ix != sz; ++ix) { /* . . . */ }
if (ix != sz)
// . . .
(b) int ix;
for (ix != sz; ++ix) { /* . . . */ }
(c) for (int ix = 0; ix != sz; ++ix, ++ sz) { /*
. . . */ }
Exercise 5.16: The while
loop is particularly good at executing while some condition holds; for example, when we need to read values until end-of-file. The for
loop is generally thought of as a step loop: An index steps through a range of values in a collection. Write an idiomatic use of each loop and then rewrite each using the other loop construct. If you could use only one loop, which would you choose? Why?
Exercise 5.17: Given two vector
s of int
s, write a program to determine whether one vector
is a prefix of the other. For vector
s of unequal length, compare the number of elements of the smaller vector
. For example, given the vector
s containing 0
, 1
, 1
, and 2
and 0
, 1
, 1
, 2
, 3
, 5
, 8
, respectively your program should return true
.
types match is to use the auto
type specifier (§ 2.5.2, p. 68). That way the compiler will deduce the type for us. If we want to write to the elements in the sequence, the loop variable must be a reference type.
On each iteration, the control variable is defined and initialized by the next value in the sequence, after which statement is executed. As usual, statement can be a single statement or a block. Execution ends once all the elements have been processed.
We have already seen several such loops, but for completeness, here is one that doubles the value of each element in a vector
:
vector<int> v = {0,1,2,3,4,5,6,7,8,9};
// range variable must be a reference so we can write to the elements
for (auto &r : v) // for each element in v
r *= 2; // double the value of each element in v
The for
header declares the loop control variable, r
, and associates it with v
. We use auto
to let the compiler infer the correct type for r
. Because we want to change the value of the elements in v
, we declare r
as a reference. When we assign to r
inside the loop, that assignment changes the element to which r
is bound.
A range for
is defined in terms of the equivalent traditional for
:
for (auto beg = v.begin(), end = v.end(); beg != end; ++beg) {
auto &r = *beg; // r must be a reference so we can change the element
r *= 2; // double the value of each element in v
}
Now that we know how a range for
works, we can understand why we said in § 3.3.2 (p. 101) that we cannot use a range for
to add elements to a vector
(or other container). In a range for
, the value of end()
is cached. If we add elements to (or remove them from) the sequence, the value of end
might be invalidated (§ 3.4.1, p. 110). We’ll have more to say about these matters in § 9.3.6 (p. 353).