range-based for loop with a iterator of reference type

Jun 26, 2014 at 4:10am
Hi, everyone. I just encountered a range-based for loop whose iterator is reference type, which confused me a lot. The code is like this. Let's assume that we have some text in a vector of strings and the name of the vector is text. Then, we can print the whole vector by the code below:
for (const auto &s : text)
cout<<s<<endl;
As what I've understood, the s here should be the iterator for the for loop and yet s has a reference type, which doesn't make much sense to me since we can never reassign a reference. When s loops through the first string in the vector, it should have been bound to it as its reference. Then, how come it can continue with the second and the rest strings?
Can someone help me out here. Thanks a lot.

Jun 26, 2014 at 7:43am
It's called a "for each" loop. It is supported in C++11, and it looks similar to how it's done in Java. If text is a list of Foo objects, s is of type Foo (the "auto" type here is convenient for that).

It's handy syntax when you don't need to know about the positioning index of the object in the list/array itself, it simply goes through *each* object.

Just as
1
2
3
4
void foo(int &var)
{
   var = 31;
} 
Changes the actual value of the parameter itself, doing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{
    int a[3] = {3, 4, 5};
    for (int &num : a)
    {
        num = num * 2; //Can change "a", since it's a reference
    }
    
    for (int i = 0; i < 3; i++)
    {
        std::cout << a[i] << std::endl;
    }
    
}

...can change "num", which is the value of the element in the array. The only reason it's
(const auto &s : text) instead of (auto s : text) is for efficiency.
Last edited on Jun 26, 2014 at 7:57am
Jun 26, 2014 at 8:11am
The 's' is not an iterator.

Your example:
1
2
3
4
for ( const auto &s : text )
{
  cout << s << endl;
}

is approximately same as this:
1
2
3
4
5
6
for ( auto i = text.begin(); i != text.end(); ++i )
{
  // decltype(i) ==  decltype(text)::iterator
  const decltype(text)::value_type & s = *i; // const string & s = *i;
  cout << s << endl;
}

Jun 26, 2014 at 1:14pm
To Ganado: not exactly what I asked, but still thanks a lot.

To keskiverto: I think I most or less understand the mechanism now after reading your reply. Does it mean that when we iterate through a for loop, each iteration has its own scope which is outside of that of the other iterations, so when i=text.begin(), we can declare a reference type variable &s here and bind it to some object and later when the iterator is incremented, i becomes (text.begin()+1) and now we can declare another reference type variable which also has the name of &s and bind it to another object since these two &s's are in two different parallel scopes. Do I get right?
Jun 26, 2014 at 1:55pm
Yes.
Jun 26, 2014 at 2:39pm
Okay, thanks a lot!
Topic archived. No new replies allowed.