Should I use std::for_each?

前端 未结 9 1312
自闭症患者
自闭症患者 2020-12-08 04:18

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

相关标签:
9条回答
  • 2020-12-08 04:49

    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, " " ) );
    
    0 讨论(0)
  • 2020-12-08 04:55

    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 returns or breaks 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:

    • returning early (even with a return value!)
    • breaking out of the loop and
    • skipping over some elements.
    0 讨论(0)
  • 2020-12-08 04:55

    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.

    0 讨论(0)
提交回复
热议问题