views:

197

answers:

6

quoting from "The C++ Standard Library" by N M Jousttis, Section 5.9


#include < iostream>
#include < list>
#include < algorithm>

using namespace std;

//function object that adds the value with which it is initialized
class AddValue {
    private:
       int the Value; //the value to add
    public:
       //constructor initializes the value to add
       AddValue(int v) : theValue(v) {    }
       //the "function call" for the element adds the value
       void operator() (int& elem) const {  elem += theValue; }
 };

int main()
{
      list<int> coll;
      for (int i=1; i<=9; ++i) 
         coll.push_back(i); 

      //The first call of for_each() adds 10 to each value:
      for_each (coll.begin(), coll.end(), AddValue(10)) ; 

Here, the expression AddValue(10) creates an object of type AddValue that is initialized with the value 10. The constructor of AddValue stores this value as the member theValue. Inside for_each(), "()" is called for each element of coll. Again, this is a call of operator () for the passed temporary function object of type AddValue. The actual element is passed as an argument. The function object adds its value 10 to each element. The elements then have the following values: after adding 10:

11 12 13 14 15 16 17 18 19

The second call of for_each() uses the same functionality to add the value of the first element to each element. It initializes a temporary function object of type AddValue with the first element of the collection:

for_each (coll.begin(), coll.end(), AddValue (*coll. begin()) ) ; 

The output is then as follows after adding first element:

22 23 24 25 26 27 28 29 30

what I don't understand is in the second case why is the output is not

22 34 35 36 37 38 39 40 41

meaning is a new functor being created for each call or is the functor used for each call ?

A: 

Yes, it is what you said. Functors are passed by value by default and thus they are copied in code of std::for_each. However you could write your own version of std::for_each explicitly stating that you want to pass functor by reference.

buratinas
A: 

Yes. A new copy of your functor is passed allong through for_each. The book you're reading explains this.

Noah Roberts
could you provide a section reference ? I am a little confused
Egon
Chapter 8 explains in more detail function objects, predicates, and what behavior you can depend on or not. For example, with predicates you can never be sure how many times your predicate object will be copied. I'm actually confused myself about your question. Why do you expect 22 34 35...?
Noah Roberts
+6  A: 

The expression AddValue(*coll. begin()) creates one temporary object of class AddValue. That temporary is then passed to the for_each function. for_each then calls the object's function call operator - that is, operator() - once for each element from coll.begin() to coll.end().

Technically, for_each takes the functor parameter by value (not reference), so a it actually operates on a copy of the temporary, not the temporary itself.

SCFrench
yes. but the question is why is it that in each call new object is not recreated, the same object is reused ? is it for some kind of parallelism ?
Egon
In this case it's academic whether the functor itself is copied; it's the face that it stores the value of what it was constructed with and not a reference (or pointer) to what it was constructed with that gives rise to the difference between the actual behaviour and what Egon seems to be expecting.
Charles Bailey
Egon - remember that for_each is just a standard function, it's not some kind of a macro. Once the values of its inputs have been computed, they are passed to the function and are not changeable. And the third argument to for_each is just an object instance, it isn't some sort of lambda for creating the functor. for_each(a, b, c) doesn't (and can't) say, "for each element of [a,b), make a new functor using the text of c and pass the element to the new functor." It says, "for each element of the range [a,b), pass the element to the specific functor instance c."
SCFrench
I get it now. Thnx
Egon
A: 

I believe the reason why the functor is copied around like this is to make for_each more general.

Imagine an implementation that took the functor by reference. That would break if the functor is an rvalue (say, if it is returned from another function):

std::for_each(first, last, get_functor(...))

Of course, in those cases, the algorithm could take the functor by const reference (since they can be bound to rvalues), but then the functor has to be const.

The only really general solution is to pass the functor by value. Then it works with const, non-const, rvalue and lvalue functors.

jalf
Charles Bailey
A: 

Your AddValue constructor takes an int so when you construct it from *coll.begin() then value of the first member of your collection is used to initialize the member variable theValue.

This is now fixed (nothing else modifies theValue) so everytime theValue is used from this AddValue object or any copies of this AddValue object it will still have the same value with which it was initialized.

This is the value that *coll.begin() had at the time the first AddValue object was constructed, not the value *coll.begin() might have been modified to.

Charles Bailey
+1  A: 

[Edit] I originally misunderstood the author's original intent. I corrected the mistake.

for_each (coll.begin(), coll.end(), AddValue (*coll. begin()) ) ;

The output is then as follows after adding first element:

22 23 24 25 26 27 28 29 30

what I don't understand is in the second case why is the output is not

22 34 35 36 37 38 39 40 41

meaning is a new functor being created for each call or is the functor used for each call ?

First of all, regardless of whether the for_each algorithm copies the functor you pass in is irrelevant. What's relevant is that you should be storing the iterator or pointer to the first element rather than the pointee. If you do that and dereference it each time, it should do the trick.

struct AddValue 
{
    const int* ptr;
    explicit AddValue(const int* iptr): ptr(iptr) {}
    void operator() (int& elem) const {elem += *ptr; }
};

int main()
{
    vector<int> v;
    for (int j=1; j <= 9; ++j)
        v.push_back(j + 10);
    for_each(v.begin(), v.end(), AddValue(&v[0]) );
    // v will be [22 34 35 36 37 38 39 40 41]
}

However, I'm going to have to throw in my two cents about functional programming. You can get really concise, cleverly-tight code through functional programming. However, it's also a big pain to debug and has the effect of decentralizing code. Unless your code can significantly benefit from it, consider simple iterator-based for loops when you can as it'll give your fellow programmers a much easier time debugging and reading through your code.

I made the mistake of getting super heavy-handed with functional programming in the past and it made my team hate me. I was obsessed with writing devilish tight code with combinatorial predicate logic and built huge libraries of function objects that could be reused over and over and in combinations. Really all I did was spend a lot of time writing functors when I could have been writing simple, equally reusable functions instead that could have been called (and inlined just as easily) from a simple iterator-based for loop (even easier to write with C++0x's range-based for loop and BOOST_FOR_EACH). I still use functional programming in C++, but sparingly. When you're going through a lot of trouble and piling on to build times to make two or three lines of code into one, you really have to ask yourself and think deeply if it's worth it and not just for yourself, but for everyone working with your code.