C++11: Sum Across a Collection of Objects Using a Lambda or a Range-Based For Loop

by Jeff Langr

January 18, 2013

I’m always disappointed when my Google search doesn’t turn up useful results on the first page. Often, an answer to a C++ question takes me to a StackOverflow page, or to a cplusplus page, where I usually find what I want. This time I didn’t find what I want on the first page (the stackoverflow link wasn’t quite it), hence this blog post.

Image source: jfgormet, Flickr

I’ve just started a series on test-focused learning (TFL) for the new C++11 features. I’m jumping the gun a little here since I’ve not yet covered lambdas (or auto, or the range-based for, or rvalue references), but I wanted searchers to have (what I think is) a better answer on the first page.

The story: Iterate a vector of objects, adding into a sum by dereferencing a member on each object, then return the sum from a function.

Here’s the declaration for the Item class:

    class Item {
       public:
          Item(int cost) : cost_{cost} {}
          int Cost() { return cost_; }
       private:
          int cost_;
    };

Here’s the assertion (I coded this test-first, of course):

    ASSERT_THAT(
       TotalCost({Item(5), Item(10), Item(15)}), 
       Eq(5 + 10 + 15));

You can get this test to pass in three statements using the range-based for loop.

    int TotalCost(vector&& items) {
       int total{0};
       for (auto item: items) total += item.Cost();
       return total;
    }

That’s clean and simple to understand, explanation of syntax barely needed.

Here’s the implementation using accumulate and a lambda.

    int TotalCost(vector&& items) {
       return accumulate(items.begin(), items.end(), 0, 
         [] (int total, Item item) { return total + item.Cost(); });
    }

That’s it. If you’re not familiar with accumulate (I wasn’t, hence my Google search), it takes a range, an initial value, and a function. If you’re not familiar with using lambdas to declare functions:

  • [] declares that the lambda requires no capture of other variables

  • between () is the parameter list for the arguments that accumulate passes to the function

  • between the {} is the function’s implementation

Which do you prefer (or neither), and why?

Comments

Franklin Chen January 18, 2013 at 2:07 pm

It should be + rather than += in

return accumulate(items.begin(), items.end(), 0,
[] (int total, Item item) { return total + item.Cost(); });

also the += happens to be legal and have a side effect that does not matter in this case.

In a toy sequential program, I don’t really care how the sum is implemented; it’s O(n) anyway. In a real program summing a huge data set, of course we would want to get parallel speedup by means of the standard map/reduce abstraction. We might not want to have a vector at all, but a parallel vector instead, for example.


Jeff Langr January 18, 2013 at 2:14 pm

Thanks Franklin,

Good catch on the +=, that was inadvertent (copied quickly from the code for the range-based for loop). Fixed.

The article is focused on readability/understanding of the C++11 features. Either construct is still applicable in non “toy” programs–not all “real” programs require that level of optimization.

-J-


Franklin Chen January 18, 2013 at 7:57 pm

I remember downloading STL using ftp from HP in 1994 over a modem Internet connection and being all excited about it, as a software engineer using C and C++ at the time, but also at the same time I was getting into functional programming. I do have to confess to having a warm fuzzy feeling about now being able to use the lambda in C++11 if were still actively programming in C++ these days. Not having to manually lambda-lift and create structs to simulate closures is going to be a big win for working C++ programmers, I predict.


christi parks January 25, 2013 at 5:53 am

I am not a programmer but I have this C language subject this session and have to prepare for it. What all topics should be covered in it?

And has anyone studied from this course http://www.wiziq.com/course/2118-learn-how-to-program-in-c-language of C tutorial online?? or tell me any other guidance…

would really appreciate help


Bret Kuhns March 25, 2013 at 8:19 am

I definitely prefer the more functional style version over the imperative loop. Looking a bit into the future, it’ll only get better with standard range-based algorithms in C++17 and the new lambda changes proposed for C++14…

return accumulate(items, 0, [] (int total, const Item& item) total + item.Cost());


Share your comment

Jeff Langr

About the Author

Jeff Langr has been building software for 40 years and writing about it heavily for 20. You can find out more about Jeff, learn from the many helpful articles and books he's written, or read one of his 1000+ combined blog (including Agile in a Flash) and public posts.