0

I am confused as to what what the difference is between for loop and for each loop in C++. I read tutorials and some books but I am yet to see how for each loop is different. With arrays, examples I have seen seem to suggest for each loop loops through the whole elements at a go. Could that be the special advantage range based loop has?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Mallam Awal
  • 223
  • 3
  • 9
  • 1
    Please update your question with specific code samples and highlight the differences that you see. – quamrana Nov 19 '19 at 11:36
  • 1
    Basically, range-based loops are faster to be typed (with less characters), while ordinary for loops are more generic. – Daniel Langr Nov 19 '19 at 11:40
  • @DanielsaysreinstateMonica That is not entirely correct. – Qix - MONICA WAS MISTREATED Nov 19 '19 at 11:41
  • 1
    Ordinary loops perform init/condition/effect, whereas foreach loops work directly with iterators. You can model one in the other, but that doesn't make them equivalents. – Qix - MONICA WAS MISTREATED Nov 19 '19 at 11:48
  • 2
    *"I read tutorials and some books"* - Can you tell us what about those tutorials confused you? Otherwise any answer we give will likely just cause the same confusion. – Galik Nov 19 '19 at 12:12
  • 1
    @Qix I would expect that as the answers. That is not the opinion, that is the fact. All of the answers available now do have an opinion based approach in them. – Croolman Nov 19 '19 at 12:15
  • The cofusion is I could see no difference substantially. So I was wondering why for each in C++11 if it brought no additional capabilities beyond traditional for loop? I wanted to confirm I had not missed something in my learning of it. – Mallam Awal Nov 19 '19 at 14:57

2 Answers2

4

The main difference is that the ordinary for-loop uses an additional variable used as an index inside the array and has the scope of the loop and you can yourself write the condition of the for loop.

For example let's assume that you need to output either all even elements of an array or until an element with a zero value is encountered. You can write

#include <iostream>

int main() 
{
    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11, 12 };
    const size_t N = sizeof( a ) / sizeof( *a );

    for ( size_t i = 0; i < N && a[i] != 0; i++ )
    {
        if ( a[i] % 2 == 0 ) std::cout << i << ": " << a[i] << '\n';
    }

    return 0;
}

The program output is

1: 2
3: 4
5: 6
7: 8

How to do this with the range-based for loop? For starters before the loop you need to declare a variable that will play the role of the index. One drawback of this is the variable is not declared in the scope where it is used.

Also to stop the iterations of the loop you need to use a break statement within the loop. That also makes the code more complicated.

Compare the above program with this

#include <iostream>

int main() 
{
    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11, 12 };
    const size_t N = sizeof( a ) / sizeof( *a );

    size_t i = 0;

    for ( const auto &item : a )
    {
        if ( item == 0 ) 
        {
            break;
        }           
        else if ( item % 2 == 0 ) 
        {
            std::cout << i << ": " << item << '\n';
        }

        ++i;
    }

    return 0;
}

In general to use the range based for loop the used container either shall have member functions begin and end or the general functions begin and end shall support the container. For arrays begin and end mean expressions a and a + N.

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Now it is getting clearer. All the while during my studies I was under the impression for each in C++11 was supposed to be a better for loop. Now I see from all the answers, each has its place. Thanks people. – Mallam Awal Nov 19 '19 at 14:49
  • 1
    @MallamAwal Usually the range-based for loop is used when you need to traverse all the array without an exception of ant its element. . – Vlad from Moscow Nov 19 '19 at 14:52
  • That was what I thought but I wasn't sure. Thanks. – Mallam Awal Nov 19 '19 at 15:01
3

The difference between a for loop and a range based for loop is roughly analogous to the difference between goto and a for loop. Former is a more generic control flow, while the latter is more structured. Every range based loop can be written as a for loop and every for loop can be written as a goto. But the reverse is not true.

Goto encapsulates the idea of jumping elsewhere. Loop encapsulates the idea of repetition (which involves jumping back). Range based loop encapsulates the idea of iterating over a range from begin until end (which involves repetition).

If your intention is to iterate over an entire range, then the range based loop is typically syntactically simpler, and easier to understand than a for loop. Likewise, a for loop is easier to understand than a goto loop. This is what makes structured approach superior. Compare for example the following, and consider which one is easier to understand:

for (auto it = list.begin(), end = list.end(); it != end; ++it) {
    auto& element = *it;
    // do stuff with element
}

for (auto& element : list) {
    // do stuff with element
}

loops through the whole elements at a go. Could that be the special advantage range based loop has?

Looping through an entire range is what range based loop can do. A for loop can do that too. But a for loop can do much more: it can iterate indices, it can iterate indefinitely, it can iterate until a terminator etc.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Maybe, it could be worth to compare a [Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for) with [std::for_each](https://en.cppreference.com/w/cpp/algorithm/for_each). If I got it right the significant difference is the execution policy which can be defined for the latter. – Scheff's Cat Nov 19 '19 at 11:42
  • @Scheff Another significant difference is that the latter requires a functor. – Daniel Langr Nov 19 '19 at 11:43
  • @DanielsaysreinstateMonica ...while the former requires a body. ;-) – Scheff's Cat Nov 19 '19 at 11:44
  • @Scheff Yes, but a functor does not have access to the current scope (unless it is captured with lambdas, which comes with its own overhead). – eike Nov 19 '19 at 11:51
  • @eike I'm not that sure that a capturing lambda means overhead per se. I once was surprised about the inlining capabilities of modern compilers when I fiddled a bit on Compiler Explorer... – Scheff's Cat Nov 19 '19 at 11:53
  • @Scheff I don't think there would be any overhead with lambdas in practice with modern compilers. I just pointed to the syntactical difference. Which is relevant to the question, IMO, since I believe the purpose of range-based loops is primarily to simplify the syntax. – Daniel Langr Nov 19 '19 at 11:59
  • @DanielsaysreinstateMonica IMHO, it's not _only_ to simplify the syntax. It can also be an opportunity to enable more aggressive optimization. If not now then, maybe, in the future. – Scheff's Cat Nov 19 '19 at 12:01
  • @Scheff I agree, compilers manage to surprise me all the time. It is just something that depends on the usage and surrounding code as well as the compiler implementation, so if there is no reason against it (readability, optimization, etc.) I tend to prefer ranged-for over `for_each`. – eike Nov 19 '19 at 12:02