Search

6.12a — For-each loops

In lesson 6.3 -- Arrays and loops, we showed examples where we used a for loop to iterate through each element of an array.

For example:

While for loops provide a convenient and flexible way to iterate through an array, they are also easy to mess up and prone to off-by-one errors.

C++11 introduces a new type of loop called a for-each loop (also called a range-based for loop) that provides a simpler and safer method for cases where we want to iterate through every element in an array (or other list-type structure).

For-each loops

The for-each statement has a syntax that looks like this:

for (element_declaration : array)
   statement;

When this statement is encountered, the loop will iterate through each element in array, assigning the value of the current array element to the variable declared in element_declaration. For best results, element_declaration should have the same type as the array elements, otherwise type conversion will occur.

Let’s take a look at a simple example that uses a for-each loop to print all of the elements in an array named fibonacci:

This prints:

0 1 1 2 3 5 8 13 21 34 55 89

Let’s take a closer look at how this works. First, the for loop executes, and variable number is set to the value of the first element, which has value 0. The program executes the statement, which prints 0. Then the for loop executes again, and number is set to the value of the second element, which has value 1. The statement executes again, which prints 1. The for loop continues to iterate through each of the numbers in turn, executing the statement for each one, until there are no elements left in the array to iterate over. At that point, the loop terminates, and the program continues execution (returning 0 to the operating system).

Note that variable number is not an array index. It’s assigned the value of the the array element for the current loop iteration.

For each loops and the auto keyword

Because element_declaration should have the same type as the array elements, this is an ideal case in which to use the auto keyword, and let C++ deduce the type of the array elements for us.

Here’s the above example, using auto:

For-each loops and references

In the for-each examples above, our element declarations are declared by value:

This means each array element iterated over will be copied into variable element. Copying array elements can be expensive, and most of the time we really just want to refer to the original element. Fortunately, we can use references for this:

In the above example, element will be a reference to the currently iterated array element, avoiding having to make a copy. Also any changes to element will affect the array being iterated over, something not possible if element is a normal variable.

And, of course, it’s a good idea to make your element const if you’re intending to use it in a read-only fashion:

Rule: Use references or const references for your element declaration in for-each loops for performance reasons.

Rewriting the max scores example using a for-each loop

Here’s the example at the top of the lesson rewritten using a for each loop:

Note that in this example, we no longer have to manually subscript the array. We can access the array element directly through variable score.

For-each loops and non-arrays

For-each loops don’t only work with fixed arrays, they work with many kinds of list-like structures, such as vectors (e.g. std::vector), linked lists, trees, and maps. We haven’t covered any of these yet, so don’t worry if you don’t know what these are. Just remember that for each loops provide a flexible and generic way to iterate through more than just arrays.

For-each doesn’t work with pointers to an array

In order to iterate through the array, for-each needs to know how big the array is, which means knowing the array size. Because arrays that have decayed into a pointer do not know their size, for-each loops will not work with them!

Similarly, dynamic arrays won’t work with for-each loops for the same reason.

Can I get the index of the current element?

For-each loops do not provide a direct way to get the array index of the current element. This is because many of the structures that for-each loops can be used with (such as linked lists) are not directly indexable!

Conclusion

For-each loops provide a superior syntax for iterating through an array when we need to access all of the array elements in forwards sequential order. It should be preferred over the standard for loop in the cases where it can be used. To prevent making copies of each element, the element declaration should ideally be a reference.

Note that because for each was added in C++11, it won’t work with older compilers.

Quiz

This one should be easy.

1) Declare a fixed array with the following names: Alex, Betty, Caroline, Dave, Emily, Fred, Greg, and Holly. Ask the user to enter a name. Use a for each loop to see if the name the user entered is in the array.

Sample output:

Enter a name: Betty
Betty was found.
Enter a name: Megatron
Megatron was not found.

Hint: Use std::string as your array type.

1) Show Solution

6.13 -- Void pointers
Index
6.12 -- Member selection with pointers and references

101 comments to 6.12a — For-each loops

  • Leea

    Alex,

    When an array element is copied (such as in the for each loop) does the copy have its own memory address? When you say making copies is expensive, is that because more memory needs to be allocated for them? I don’t understand what is happening behind the scenes when a copy is being made of a variable or array element.

    Thank you in advance 🙂

    • Alex

      Yes, copies have their own memory addresses (as copies need to live _somewhere_ in memory). Copies are “expensive” because the CPU (at runtime) needs to copy however many bytes are in the source object into the destination object. For example, let’s say we had a struct that was 1000 bytes in size. If we made a copy of that struct, the CPU would have to copy 1000 bytes from the original struct into the copied struct. It’s not the 1000 bytes of memory being used temporarily that’s the issue (because the copy will get destroyed when it goes out of scope anyway), it’s the time taken to duplicate the object in memory that’s the issue.

      Additionally, copying classes is even more expensive because they have special functions that run to create and destroy them (constructors and destructors). This takes even more time.

      Copying a pointer or reference, on the other hand, typically only involves copying 4 or 8 bytes of data, which is much less.

  • Nicolas

    Hello Alex, I’m having issues with the code that I wrote for the quiz.

    I get an error at if (bool nameEntered == true) and at else if (bool nameEntered == false). I thought making a boolean to check if the user typed in one of the names would be smart, but i dont know why it doesnt just check if nameEntered is true or false. “expression preceding parenthesis of apparent call must be a pointer-to funtion type” is what it says

    • Alex

      There are three issues here:
      1) Inside the upper if/else, you’re declaring nameEntered as a local variable to the block it’s defined in. That means it gets destroyed at the end of the block. By the time we get down to the lower if/else, nameEntered has already been destroyed. Fix: Define nameEntered once before the for loop.
      2) You’re not stopping the loop when determining that nameEntered is true, so if the user enters any name other than Holly, the loop will set nameEntered to false. Fix: Initialize nameEntered to false, and then set it to true if any of the names match.
      3) In the lower if/else, you’re doing a comparison incorrectly. The compiler thinks nameEntered(true) is a function call and it can’t find a function with that name (same for the false case). Fix: Use nameEntered == true.

  • AMG

    Cannot figure out why enum type is not allowed in for-each loop. Any thoughts? Thanks.

    • Alex

      It is allowed:

  • Michele

    Hi Alex!

    First of all I wanted to thank you for these wonderful tutorials, I really am learning a lot!

    Second, I think there is a mistake in the quiz’ solution: that break shouldn’t be there.
    If username isn’t equal to the first element of the array, it exits the loop without looping through the rest.

    • Alex

      No, it’s correct as written. If the username isn’t equal to the first element of the array, this line will evaluate to false:

      So the break will never execute until name == username, at which point we have a definitive answer and can exit the loop.

      • Michele

        I looked again at my code and saw I made a stupid mistake. My if-statement was inside the curly brackets… Thanks for the quick reply!

  • justAnotherConfusedStudent

    For your max scores rewritten example, would it be more efficient if we iterated over a reference instead of just score (like below)?

    • Alex

      When your array is a fundamental type, iterating by value is okay since making a copy of the element isn’t more expensive than setting up a reference.

      But I agree, using a const reference here is probably a better choice. I’ll update the example.

  • C++ Learner

    when found gets out from for loop it becomes true?(bool found=true)

    • Alex

      found gets set to true if name==username for any of the loop iterations. It will keep whatever value it was last set to even outside of the loop.

  • James

    iterate through each element in array
    iterate through each element in the array
    Although I guess if the variable is actually called array then the grammar makes sense.

  • Dani

    #include <iostream>
    #include <string>

    using namespace std;
    int main()
    {  string name[] ={"Alex", "Betty", "Caroline", "Dave","Emily", "Fred", "Greg","Holly"} ;
       string input_name ;
       cin >> input_name ;
       for (auto print : name )
       {
          if (input_name == print )
          {
           cout << input_name << " was found ";
           return 0 ;
          }
       }
          cout << input_name << " Not found " ;
      
       return 0 ;
       }
    what do you think about my code ?
    i’m sorry i dont know how to use syntax highlighter

  • thang

    Alex, can you write a code illustrate  that for-each loop can work with structure.  Thank you

    • Alex

      I’m not sure I understand what you’re asking. Are you asking if a for-each loop can step through each member of a struct? If so, the answer is no.

  • Saiteja Muppavarapu

    Hello,
    As has been said in the lesson on reference variables, a reference once initialised cannot be reassigned or redirected to reference another variable. Then, how do for each loops work when you use a reference to iterate through an array?

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter