C++11 range-based for loop

In this post we will discuss in detail about the C++11 range based for loop.We will see how it is more efficient than the normal ‘for’ loop and why it should be preferred?

In a normal for loop statement-inherited from C- we usually write three expressions separated by ‘;‘(semi-colon) to specify the condition of the iteration.The ‘for’ statement iterates the specified number of times during which we perform various operations.

Unlike the C98 ‘for statement’ the C++11 range-based for loop allows iterating ‘for’ statement using a simpler syntax and expression.The general syntax of range-based for loop is.

for(declaration : expression)
{
 //your code
}

declaration: This is usually a variable of the type from which we want to access the value.

expression: This is a name of the container or any equivalent storage(say an array) from which we would access the value.

Using range-based for loop with built-in type

Let us use a range-based for loop to access an array.

int arr[]={ 12 , 45 , 90};
for( int elem : arr )
{
cout<< elem << ” ” ;
}

Output

12 45 90

In the above code instead of specifying the type literally like the ‘int’ for ‘elem’ variable,we can use the C++11 feature ‘auto‘ and let the compiler specify the type for us automatically.So re-writting the above code using ‘auto’ the program is given below.

Link :C++11 auto keyword

 for( auto elem:arr )
{
cout<< elem << ” ” ;
}

Output

12 45 90

Here we have used ‘auto’ instead of ‘int’ and also using the range-based for loop we have accessed all the elements of the ‘arr’ array.I am sure this method is simpler than the traditional ‘for loop’ statement.



Using range-based for loop with STL containers

We can also use range-based for loop to access the content of the STL containers.Lets directly jump to the code example given below.

vector<string> vec={ “Sad” , “happy” , “anger” };

for(auto elem:vec)
{
cout<< elem << ” ” ;
}

Output

Sad happy anger

This is same as using the iterator to access the vector.

for(vector<string>::iterator elem=vec.begin( ) ; elem!=vec.end( ); elem++ )
{
cout<< *elem << ” ” ;
}

Output

Sad happy anger


Using reference as a declaration inside ranged-based for loop

Whenever you want to change the value of the array or collection of objects using the range-based for loop make sure that you use a reference instead of the normal declaration.Consider an example below which uses the normal declaration.

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

for( auto elem:arr )
{
elem=elem*elem ;
cout<< elem << endl ;
}

cout<< endl << arr[0] << ” ” << arr[1] ;

Output

1
4
9
16

1 2

Although the value is changed inside the for statement,the changes is not seen outside the for statement.Only the local variable ‘elem’ value is changed which has a local scope.

Consider the picture below.

C++11 range based for loop

The value of the array is copied to the ‘elem’ storage as we iterate through the loop.So in fact we are accessing the value in ‘elem’ storage not the actual value of the array.

Using reference

If we use a reference we are directly accessing the storage of the array,so the changes will be seen outside the for statement.Consider the code example given below.

 for(auto &elem:arr )
{
elem=elem*elem ;
}
cout<< arr[0] << ” ” << arr[1] << ” ” << arr[2] << endl ;

Output

1 4 9

Use reference is you wish to change the value of the array or any container when using range-based for loop.



When the data type is a class or struct

In class or struct array or a container holding class object,the range-based for loop can be implemented in the same way as the built-in type.Here in each iteration the variable will point to the object of the type.

class A
{
 string st;

public:
 A(string s):st(s) { }

 string get() const { return st; }

 ~A( ) { }
};

int main( )
{
vector<A > vecA={ A(“He Man”) , A(“Thunder Cat”) , A(“Mummy”) };

for(auto elem:vecA)
{
cout<< elem.get() << endl ;
}

return 0;
}

Output

He Man
Thunder cat
Mummy

‘elem’ point to A object and we call get() to access the data member of the object.There is no new implementation here,it’s what we have been doing.

implicit conversion is not allowed in range-based for loop

If the constructor of the class accepts only explicit type than the declaration in the range-based for loop does not allow implicit conversion.Consider the code below.

//Class A
class A
{
 string st;

public:
 A(string s):st(s) { }

 string get() const { return st; }

 ~A( ) { }
};

/*Class B,the constructor accept only explicit type **/
class B
{
 int i;

public:
 explicit B(int val):i(val) { } 

 int get() const { return i; }

 ~B( ) { }
};

int main( )
{
vector<int> vecI={12 , 4 , 40};

for( B elem:vecI ) //error!!!
{
cout<< elem.get();
}

vector<string> vecS={” 89″ , ” 2012 the end” };

for(A elem:vecS) //work fine
{
cout<< elem.get() ;
}

return 0;
}

In the first ‘for’ loop(line 31 for PC user) the constructor of B allows only explicit type.This provide constraint from converting the elements of vecI to B object type.However,in the second for loop()(line 38) there is no such restriction impose by the A constructor.Thus,vecS elements is converted to A object type.And the code execute smoothly!!