12

I know how this loop works, and how I can use it in practical problems. But I want to know what is happening under the hood. I thought that this loop was similar to a regular for loop in which for example

for(int i = 0 ; i < 5 ; i ++){ // instructions } 

Variable i is initialized only once, so I thought that this was the same for range based loops. But if I for example write this code:

for(const int x : vec) { cout << x << endl; } 

The compiler lets me to do this, but I don't understand how this is possible. If variable x is const, how come in every iteration the x value is different?

1
  • FYI it's closer to for (auto iter = vec.begin(); iter != vec.end(); ++iter) Commented Nov 5, 2015 at 22:45

3 Answers 3

18

Every iteration of the loop creates a local variable x and initializes it to the next element of vec. When the loop iteration ends, x goes out of scope. A single x is never modified.

See this link for the precise semantics.

Sign up to request clarification or add additional context in comments.

Comments

3

The range-based for-loop is indeed somewhat different than the classical for-loop in this regard. The declaration you provide (const int x) is declared for every iteration separately, in contrast to classical for-loops.

To be more precise:

for (const int x : vec) { cout << x << endl; } 

is just a shorthand for (and simply replaced with) the following "classical iterator loop":

for (auto it = vec.begin(), e = vec.end(); it != e; ++it) { const int x = *it; cout << x << endl; } 

(except that it and e are not available in the body; also vec is actually "saved" in a separate variable; but let's not focus on unimportant details here; the exact definition of range-based for loop can be looked up here)

Note that const int x is declared and initialized to *it inside the loop body! So it is initialized in every iteration, rather than changed.

Comments

2

For unterstanding purpose you can think of it as if the compiler is replacing for (auto x: y) {...} with for (auto i = begin(y), end = end(y); i != end; ++i) { auto x = *i; {...} }.

For std::vector begin(y)/end(y) will resolve (via the adl) to std::begin(y)/std::end(y) versions that would call y.begin()/y.end() respectively.

4 Comments

more or less. For understanding it's perfect, but you should at least tell that the syntax is a little more complicated in reality
That's not quite accurate. Imagine y is make_temporary().
i != end, not i < end.
@leemes: I've found it useful to be precise when describing C++, since seemingly unimportant details can become important when you least expect it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.