Advantages of Std::For_Each Over for Loop

Advantages of std::for_each over for loop

The nice thing with C++11 (previously called C++0x), is that this tiresome debate will be settled.

I mean, no one in their right mind, who wants to iterate over a whole collection, will still use this

for(auto it = collection.begin(); it != collection.end() ; ++it)
{
foo(*it);
}

Or this

for_each(collection.begin(), collection.end(), [](Element& e)
{
foo(e);
});

when the range-based for loop syntax is available:

for(Element& e : collection)
{
foo(e);
}

This kind of syntax has been available in Java and C# for some time now, and actually there are way more foreach loops than classical for loops in every recent Java or C# code I saw.

Why use std::for_each over a for loop?

It depends somewhat on the local coding conventions, but there are two
potential advantages. The first is that it states clearly that the code
iterates over all of the elements in the sequence; unless the local
coding conventions say otherwise (and they are enforced), you have to
consider that some cowboy programmer might have inserted a break. The
second is that it names the operation you are performing on each
element; this once can easily be handled by calling a function in the
loop, and of course, really trivial operations may not need a name.

There's also the advantage, at least if you aren't yet using C++11, that
you don't have to spell out the iterator types; the spelled out iterator
types create a lot of verbiage, in which the important logic can get
lost or overlooked.

Should I use std::for_each?

There is an advantage to using std::for_each instead of an old school for loop (or even the newfangled C++0x range-for loop): you can look at the first word of the statement and you know exactly what the statement does.

When you see the for_each, you know that the operation in the lambda is performed exactly once for each element in the range (assuming no exceptions are thrown). It isn't possible to break out of the loop early before every element has been processed and it isn't possible to skip elements or evaluate the body of the loop for one element multiple times.

With the for loop, you have to read the entire body of the loop to know what it does. It may have continue, break, or return statements in it that alter the control flow. It may have statements that modify the iterator or index variable(s). There is no way to know without examining the entire loop.

Herb Sutter discussed the advantages of using algorithms and lambda expressions in a recent presentation to the Northwest C++ Users Group.

Note that you can actually use the std::copy algorithm here if you'd prefer:

std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, "\n"));

for loop vs std::for_each with lambda

I think there are some other differences not yet covered by the answers so far.

  1. a for_each can accept any appropriate callable object, allowing one to 'recycle' the loop body for different for loops. For example (pseudo code)

    for( range_1 ) { lengthy_loop_body }    // many lines of code
    for( range_2 ) { lengthy_loop_body } // the same many lines of code again

    becomes

    auto loop_body = some_lambda;           // many lines of code here only
    std::for_each( range_1 , loop_body ); // a single line of code
    std::for_each( range_2 , loop_body ); // another single line of code

    thus avoiding duplication and simplifying code maintenance. (Of course, in a funny mix of styles one could also use a similar approach with the for loop.)

  2. another difference regards breaking out of the loop (with break or return in the for loop). As far as I know, in an for_each loop this can only be done by throwing an exception. For example

    for( range )
    {
    some code;
    if(condition_1) return x; // or break
    more code;
    if(condition_2) continue;
    yet more code;
    }

    becomes

    try {
    std::for_each( range , [] (const_reference x)
    {
    some code;
    if(condition_1) throw x;
    more code;
    if(condition_2) return;
    yet more code;
    } );
    } catch(const_reference r) { return r; }

    with the same effects regarding calling of destructors for objects with scope of the loop body and the function body (around the loop).

  3. the main benefit of for_each is, IMHO, that one can overload it for certain container types, when plain iteration is not as efficient. For example, consider a container that holds a linked list of data blocks, each block containing a contiguous array of elements, similar to (omitting irrelevant code)

    namespace my {
    template<typename data_type, unsigned block_size>
    struct Container
    {
    struct block
    {
    const block*NEXT;
    data_type DATA[block_size];
    block() : NEXT(0) {}
    } *HEAD;
    };
    }

    then an appropriate forward iterator for this type would require to check for the end of block at each increment and the comparison operator needs to compare both the block pointer and the index within each block (omitting irrelevant code):

    namespace my {
    template<typename data_type, unsigned block_size>
    struct Container
    {
    struct iterator
    {
    const block*B;
    unsigned I;
    iterator() = default;
    iterator&operator=(iterator const&) = default;
    iterator(const block*b, unsigned i) : B(b), I(i) {}
    iterator& operator++()
    {
    if(++I==block_size) { B=B->NEXT; I=0; } // one comparison and branch
    return*this;
    }
    bool operator==(const iterator&i) const
    { return B==i.B && I==i.I; } // one or two comparisons
    bool operator!=(const iterator&i) const
    { return B!=i.B || I!=i.I; } // one or two comparisons
    const data_type& operator*() const
    { return B->DATA[I]; }
    };
    iterator begin() const
    { return iterator(HEAD,0); }
    iterator end() const
    { return iterator(0,0); }
    };
    }

    this type of iterator works correctly with for and for_each, for example

    my::Container<int,5> C;
    for(auto i=C.begin();
    i!=C.end(); // one or two comparisons here
    ++i) // one comparison here and a branch
    f(*i);

    but requires two to three comparisons per iteration as well as a branch. A more efficient way is to overload the for_each() function to loop on the block pointer and index separately:

    namespace my {
    template<typename data_type, int block_size, typename FuncOfDataType>
    FuncOfDataType&&
    for_each(typename my::Container<data_type,block_size>::iterator i,
    typename my::Container<data_type,block_size>::iterator const&e,
    FuncOfDataType f)
    {
    for(; i.B != e.B; i.B++,i.I=0)
    for(; i.I != block_size; i.I++)
    f(*i);
    for(; i.I != e.I; i.I++)
    f(*i);
    return std::move(f);
    }
    }
    using my::for_each; // ensures that the appropriate
    using std::for_each; // version of for_each() is used

    which requires only one comparison for most iterations and has no branches (note that branches can have a nasty impact on performance). Note that we don't need to define this in namespace std (which might be illegal), but can ensure that the correct version is used by appropriate using directives. This is equivalent to using std::swap; when specialising swap() for certain user-defined types.

Preferred standard use: range based for or std::for_each

  1. Range-based for is obviously simpler to read and write. It is specialized for this task.

    EDIT: You can break form a range-for without abusing an exception. (Although std::find_if substituted for std::for_each allows this as well.)

  2. std::for_each, ironically, is the alternative which is actually range based and allows you to select particular begin and end values instead of the whole container. (EDIT: This can be hacked around using a simple range class providing begin and end members, such as provided by Boost.)

    Also for_each may be more elegant when otherwise using higher-order functions: it can be used as an argument to bind, and the third argument is already a functor.

Mainly it's a matter of style. Most readers probably prefer to see for ( auto &a : b ) though, and most implementations now support it.

How to write this for-loop using std::for_each or std::transform?

I wouldn't change this to use one of the algorithms unless you have a compiler that supports lambdas. It's completely clear as written. Even if your compiler did support lambdas, I'd probably not change this code.

One relatively straightforward option would be to write a flattening iterator. I wrote one for demonstration in an answer to another question.

If you really want a one-liner and can use bind (boost::bind from Boost, std::tr1::bind from TR1, and std::bind from C++0x will all work), then here is how that would look. I warn you in advance: it is horrible.

Edit: Technically this is also illegal. The type of a Standard Library member function is unspecified, so you cannot (portably or correctly) take the address of such a member function. If you could correctly take the address of a Standard Library member function, this is what it would look like:

typedef std::vector<int>::iterator (std::vector<int>::*IteratorGetter)();

std::for_each(int_vectors.begin(), int_vectors.end(),
std::bind(
std::bind(
&std::vector<int>::insert<std::vector<int>::iterator>,
&ints,
std::bind((IteratorGetter)&std::vector<int>::end, &ints),
_1,
_2
),
std::bind((IteratorGetter)&std::vector<int>::begin, _1),
std::bind((IteratorGetter)&std::vector<int>::end, _1)
)
);

(Yes, that is technically one "line of code" as it is a single statement. The only thing I have extracted is a typedef for the pointer-to-member-function type used to disambiguate the overloaded begin and end functions; you don't necessarily have to typedef this, but the code requires horizontal scrolling on Stack Overflow if I don't.)

Can each Iteration of a for loop/for_each be done in parallel? (C++11)

You can do something like this

for(T& d : data) std::thread(DoTask, d).detach();

Or you can use something more complicated like Intel's Thread Building Blocks and the parallel_for (isn't that the name?) function thereof.



Related Topics



Leave a reply



Submit