4

I have been messing with range-based for loops, like this one:

int a[] = {1, 2, 3, 4};

for(auto i : a){
    cout << i;
}

(Correct me here if I'm wrong)I suppose that i assigned at start of every iteration with the next value in sequence container a like:

i = a[0] … iteration 1

i = a[1] … iteration 2

i = a[9] … iteration 10

I wanted to ask how does this works when loop control variable is a reference:

for(int &i : a){...}

Since a reference is not assigned at initialization but binded, and the binding never changes then how does i iterates through a saving value of an element of a in a given iteration but when a reference is assigned except in the declaration it is like assigning the original variable. To change array elements we have to use reference, my question is how a single reference can be binded to different variables(i.e. elements of a during looping) as every element can be modified with the same reference variable inside the loop.

Thanks

cigien
  • 57,834
  • 11
  • 73
  • 112
dev
  • 219
  • 1
  • 2
  • 13
  • 2
    `i` is a local variable within the loop. Essentially, a new instance is declared and initialized each time through the loop. See also [this article](https://en.cppreference.com/w/cpp/language/range-for) - it shows how a range-for loop is rewritten by the compiler into a "normal" loop. – Igor Tandetnik Sep 03 '18 at 16:55
  • @IgorTandetnik I may be wrong but I thought that range-based for loop may be similar to usual for loop that maintains a single control variable that can be incremented or decremented. And the link you mentioned, I can't understand the example, can you please explain it in a simple way, an answer would be better if you can. – dev Sep 03 '18 at 17:10
  • 2
    Your loop is rewritten by the compiler as `for (auto iter = std::begin(a); iter != std::end(a); ++iter) { int& i = *iter; ...}` In this case, `iter` is simply `int*` pointer. – Igor Tandetnik Sep 03 '18 at 17:12
  • 1
    Does this answer your question? [C++11 range based loop: get item by value or reference to const](https://stackoverflow.com/questions/15176104/c11-range-based-loop-get-item-by-value-or-reference-to-const) – cigien Oct 28 '20 at 17:15

2 Answers2

5

I found this informative article that will help you:

I think the below quote from the article answers your question:

In the range based for loop, auto& will create references (plural) to the original elements in the range.

Also the different ways of using auto in a range-based for loop are covered in it.


for (auto x : range)

This will create a copy of each element in the range. Therefore, use this variant when you want to work with a copy.


for (const auto x : range)

The use of const auto may suggest that you want to work with an immutable copy of each element.


for (auto& x : range)

Use auto& when you want to modify elements in the range in non-generic code.


for (const auto& x : range)

Use const auto& when you want read-only access to elements in the range, even in generic code


for (auto&& x : range)

Use auto&& when you want to modify elements in the range in generic code


for (const auto&& x : range)

This variant will bind only to rvalues, which you will not be able to modify or move because of the const. This makes it less than useless. Hence, there is no reason for choosing this variant over const auto&.


for (decltype(auto) x : range) // C++14

It means: apply automatic type deduction, but use decltype rules. Whereas auto strips down top-level cv qualifiers and references, decltype preserves them.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • I got the point just one more question: How multiple references of same name x can be declared and used? (or is it that x is declared at the beginning of each iteration and previous copy is destroyed) – dev Sep 04 '18 at 15:07
  • How it is done exactly is up to the compiler. The compiler will follow the rules governing range based for loop defined in the Cpp standard. Any implementation which confirms to the standard is acceptable. – P.W Sep 04 '18 at 15:51
  • but it is true that multiple references are declared for each element in sequence? – dev Sep 04 '18 at 15:56
  • Not multiple references for each element but one reference for the current element in every iteration. That's how I understand that statement I quoted from the article. – P.W Sep 04 '18 at 16:27
  • meaning a new reference in every iteration? – dev Sep 04 '18 at 16:48
  • Yes, but with the same name. – P.W Sep 04 '18 at 17:05
1

Simple idea is similar to STL iterator. You can think a similar approach to iterator based for loop as well e.g.

for(auto it = a.begin(); it != a.end(); it++){ .... }

Now, for range based approach, at each iteration your reference moves to next memory location and access to referenced location can change whatever you need.

for(int& i : a) { ... } 

i references to memory location 0xffffcbd0 at first iteration.
i references to memory location 0xffffcbd4 at second iteration.

... and so on.

Try to print memory positions of i with &i.

for(int& i : a) { 
    cout<<i<<endl;
    cout<<&i<<endl;
} 
badola
  • 820
  • 1
  • 13
  • 26
O Dundar
  • 90
  • 1
  • 6
  • But the problem is references are binded only once, how the same reference variable can point to different locations at different points of execution. – dev Sep 04 '18 at 15:01
  • @dev once per compound statement. But it is bound every time enter that statement's scope. Which is each iteration – Swift - Friday Pie Oct 28 '20 at 23:42