Advantages of std::for_each over for loop

后端 未结 21 633
遥遥无期
遥遥无期 2020-11-29 15:23

Are there any advantages of std::for_each over for loop? To me, std::for_each only seems to hinder the readability of code. Why do then some coding

相关标签:
21条回答
  • 2020-11-29 15:58

    Like many of the algorithm functions, an initial reaction is to think it's more unreadable to use foreach than a loop. It's been a topic of many flame wars.

    Once you get used to the idiom you may find it useful. One obvious advantage is that it forces the coder to separate the inner contents of the loop from the actual iteration functionality. (OK, I think it's an advantage. Other's say you're just chopping up the code with no real benifit).

    One other advantage is that when I see foreach, I know that either every item will be processed or an exception will be thrown.

    A for loop allows several options for terminating the loop. You can let the loop run its full course, or you can use the break keyword to explicitly jump out of the loop, or use the return keyword to exit the entire function mid-loop. In contrast, foreach does not allow these options, and this makes it more readable. You can just glance at the function name and you know the full nature of the iteration.

    Here's an example of a confusing for loop:

    for(std::vector<widget>::iterator i = v.begin(); i != v.end(); ++i)
    {
       /////////////////////////////////////////////////////////////////////
       // Imagine a page of code here by programmers who don't refactor
       ///////////////////////////////////////////////////////////////////////
       if(widget->Cost < calculatedAmountSofar)
       {
            break;
       }
       ////////////////////////////////////////////////////////////////////////
       // And then some more code added by a stressed out juniour developer
       // *#&$*)#$&#(#)$#(*$&#(&*^$#(*$#)($*#(&$^#($*&#)$(#&*$&#*$#*)$(#*
       /////////////////////////////////////////////////////////////////////////
       for(std::vector<widgetPart>::iterator ip = widget.GetParts().begin(); ip != widget.GetParts().end(); ++ip)
       {
          if(ip->IsBroken())
          {
             return false;
          }
       }
    }
    
    0 讨论(0)
  • 2020-11-29 15:58

    There are a lot of good reasons in other answers but all seem to forget that for_each allows you to use reverse or pretty much any custom iterator when for loop always starts with begin() iterator.

    Example with reverse iterator:

    std::list<int> l {1,2,3};
    std::for_each(l.rbegin(), l.rend(), [](auto o){std::cout<<o;});
    

    Example with some custom tree iterator:

    SomeCustomTree<int> a{1,2,3,4,5,6,7};
    auto node = a.find(4);
    std::for_each(node.breadthFirstBegin(), node.breadthFirstEnd(), [](auto o){std::cout<<o;});
    
    0 讨论(0)
  • 2020-11-29 16:01

    for_each is more generic. You can use it to iterate over any type of container (by passing in the begin/end iterators). You can potentially swap out containers underneath a function which uses for_each without having to update the iteration code. You need to consider that there are other containers in the world than std::vector and plain old C arrays to see the advantages of for_each.

    The major drawback of for_each is that it takes a functor, so the syntax is clunky. This is fixed in C++11 (formerly C++0x) with the introduction of lambdas:

    std::vector<int> container;
    ...
    std::for_each(container.begin(), container.end(), [](int& i){
        i+= 10;
    });
    

    This will not look weird to you in 3 years.

    0 讨论(0)
  • 2020-11-29 16:01

    for_each allow us to implement Fork-Join pattern . Other than that it supports fluent-interface.

    fork-join pattern

    We can add implementation gpu::for_each to use cuda/gpu for heterogeneous-parallel computing by calling the lambda task in multiple workers.

    gpu::for_each(users.begin(),users.end(),update_summary);
    // all summary is complete now
    // go access the user-summary here.
    

    And gpu::for_each may wait for the workers work on all the lambda-tasks to finish before executing the next statements.

    fluent-interface

    It allow us to write human-readable code in concise manner.

    accounts::erase(std::remove_if(accounts.begin(),accounts.end(),used_this_year));
    std::for_each(accounts.begin(),accounts.end(),mark_dormant);
    
    0 讨论(0)
  • 2020-11-29 16:03

    I find for_each to be bad for readability. The concept is a good one but c++ makes it very hard to write readable, at least for me. c++0x lamda expressions will help. I really like the idea of lamdas. However on first glance I think the syntax is very ugly and I'm not 100% sure I'll ever get used to it. Maybe in 5 years I'll have got used to it and not give it a second thought, but maybe not. Time will tell :)

    I prefer to use

    vector<thing>::iterator istart = container.begin();
    vector<thing>::iterator iend = container.end();
    for(vector<thing>::iterator i = istart; i != iend; ++i) {
      // Do stuff
    }
    

    I find an explicit for loop clearer to read and explicity using named variables for the start and end iterators reduces the clutter in the for loop.

    Of course cases vary, this is just what I usually find best.

    0 讨论(0)
  • 2020-11-29 16:04

    If you frequently use other algorithms from the STL, there are several advantages to for_each:

    1. It will often be simpler and less error prone than a for loop, partly because you'll be used to functions with this interface, and partly because it actually is a little more concise in many cases.
    2. Although a range-based for loop can be even simpler, it is less flexible (as noted by Adrian McCarthy, it iterates over a whole container).
    3. Unlike a traditional for loop, for_each forces you to write code that will work for any input iterator. Being restricted in this way can actually be a good thing because:

      1. You might actually need to adapt the code to work for a different container later.
      2. At the beginning, it might teach you something and/or change your habits for the better.
      3. Even if you would always write for loops which are perfectly equivalent, other people that modify the same code might not do this without being prompted to use for_each.
    4. Using for_each sometimes makes it more obvious that you can use a more specific STL function to do the same thing. (As in Jerry Coffin's example; it's not necessarily the case that for_each is the best option, but a for loop is not the only alternative.)

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