Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm wondering why functors are passed by copy to the algorithm functions:

template <typename T> struct summatory
{
    summatory() : result(T()) {}

    void operator()(const T& value)
    { result += value; std::cout << value << "; ";};

    T result;
};

std::array<int, 10> a {{ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 }};
summatory<int> sum;

std::cout << "
The summation of: ";
std::for_each(a.begin(), a.end(), sum);
std::cout << "is: " << sum.result;

I was expecting the following output:

The summation of: 1; 1; 2; 3; 5; 8; 13; 21; 34; 55; is: 143

But sum.result contains 0, that is the default value assigned in the ctor. The only way to achieve the desired behaviour is capturing the return value of the for_each:

sum = std::for_each(a.begin(), a.end(), sum);
std::cout << "is: " << sum.result;

This is happening because the functor is passed by copy to the for_each instead of by reference:

template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

So the outer functor remains untouched, while the inner one (which is a copy of the outer) is updated and is returned after perform the algorithm (live demo), so the result is copied (or moved) again after doing all the operations.


There must be a good reason to do the work this way, but I don't really realize the rationale in this design, so my questions are:

  • Why the predicates of the sequence-operation algorithms are passed by copy instead of reference?
  • What advantages offers the pass-by-copy approach in front of the pass-by-reference one?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
134 views
Welcome To Ask or Share your Answers For Others

1 Answer

It's mostly for historic reasons. At '98 when the whole algo stuff made it into the standard references had all kind of problems. That got eventually resolved through core and library DRs by C++03 and beyond. Also sensible ref-wrappers and actually working bind only arrived only in TR1.

Those who tried use algos with early C++98 having functions using ref params or returns can recall all kind of trouble. Self-written algos were also prone to hit the dreaded 'reference to reference' problem.

Passing by value at least worked fine, and hardly created many problems -- and boost had ref and cref early on to help out where you needed to tweak.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...