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.
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 againbecomes
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 codethus 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.)another difference regards breaking out of the loop (with
break
orreturn
in thefor
loop). As far as I know, in anfor_each
loop this can only be done by throwing an exception. For examplefor( 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).
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
andfor_each
, for examplemy::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 usedwhich 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 appropriateusing
directives. This is equivalent tousing std::swap;
when specialisingswap()
for certain user-defined types.
Preferred standard use: range based for or std::for_each
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 forstd::for_each
allows this as well.)std::for_each
, ironically, is the alternative which is actually range based and allows you to select particularbegin
andend
values instead of the whole container. (EDIT: This can be hacked around using a simplerange
class providingbegin
andend
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 tobind
, 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
Multiset, Map and Hash Map Complexity
C++ Access Derived Class Member from Base Class Pointer
How to Change the Variable to Which a C++ Reference Refers
What Is Return Type of Assignment Operator
How to Use an Array as Map Value
When Is It Worthwhile to Use Bit Fields
In C++, How to Forward Declare a Class as Inheriting from Another Class
How Does a 32 Bit Processor Support 64 Bit Integers
Are There Stackless or Heapless Implementation of C++
Unoptimized Clang++ Code Generates Unneeded "Movl $0, -4(%Rbp)" in a Trivial Main()
Will an 'Empty' Constructor or Destructor Do the Same Thing as the Generated One
What Does the Fpermissive Flag Do
Initialise Eigen::Vector with Std::Vector
Thread Safe Implementation of Circular Buffer
Disambiguate Overloaded Member Function Pointer Being Passed as Template Parameter