I\'m always trying to learn more about the languages I use (different styles, frameworks, patterns, etc). I\'ve noticed that I never use std::for_each so I thought that perh
Well... that works, but for printing a vector (or the content of other container types) I prefer this :
std::copy(v.begin(), v.end(), std::ostream_iterator< int >( std::cout, " " ) );
It depends.
The power of for_each
is, that you can use it with any container whose iterators satisfy the input iterator concept and as such it's generically useable on any container. That increases maintainability in a way that you can just swap out the container and don't need to change anything. The same doesn't hold true for a loop over the size
of a vector. The only other containers you could swap it with without having to change the loop would be another random-access one.
Now, if you'd type out the iterator version yourself, the typical version looks like this:
// substitute 'container' with a container of your choice
for(std::container<T>::iterator it = c.begin(); it != c.end(); ++it){
// ....
}
Rather lengthy, eh? C++0x relieves us of that length thing with the auto
keyword:
for(auto it = c.begin(); it != c.end(); ++it){
// ....
}
Already nicer, but still not perfect. You're calling end
on every iteration and that can be done better:
for(auto it = c.begin(), ite = c.end(); it != ite; ++it){
// ....
}
Looks good now. Still, longer than the equivalent for_each
version:
std::for_each(c.begin(), c.end(), [&](T& item){
// ...
});
With "equivalent" being slightly subjective, as the T
in the parameter list of the lambda could be some verbose type like my_type<int>::nested_type
. Though, one can typedef
his/her way around that. Honestly, I still don't understand why lambdas weren't allowed to be polymorphic with type deduction...
Now, another thing to consider is that for_each
, the name itself, already expresses an intent. It says that no elements in the sequence will be skipped, which might be the case with your normal for-loop.
That brings me to another point: Since for_each
is intended to run over the whole sequence and apply an operation on every item in the container, it is not designed to handle early return
s or break
s in general. continue
can be simulated with a return
statement from the lambda / functor.
So, use for_each
where you really want to apply an operation on every item in the collection.
On a side note, for_each
might just be "deprecated" with C++0x thanks to the awesome range-based for-loops (also called foreach loops):
for(auto& item : container){
// ...
}
Which is way shorter (yay) and allows all three options of:
I generally would recommend use of std::for_each
. Your example for loop does not work for non-random-access containers. You can write the same loop using iterators, but it's usually a pain due to writing out std::SomeContainerName<SomeReallyLongUserType>::const_iterator
as the type of the iteration variable. std::for_each
insulates you from this, and also amortizes the call to end
automatically.