Passing a functor object by value vs by reference (C ++)

Compare common integration features:

template <class F> double integrate(F integrand); 

from

 template <class F> double integrate(F& integrand); 

or

 template <class F> double integrate(const F& integrand); 

What are the pros and cons of each? STL uses the first approach (passed by value), does it mean the most universal?

+13
c ++ templates
source share
3 answers

Function objects usually should be small, so I don’t think that their transfer in value will differ markedly from performance (compare it with the work performed by the function in your body). If you pass by value, you can also get code analysis because the parameter by value is local to the function, and the optimizer can tell when and when data loading from the functor data element cannot be omitted.

If the functor does not have a state, then passing it as an argument does not imply any cost - the fill byte that the functor accepts does not have to have any special value (in Itanium Abi, used by GCC, at least). When using links, you always need to pass the address.

The latter ( const T& ) has a drawback that in C ++ 03 does not work for raw functions, because in C ++ 03 the program is poorly formed if you try to apply const to the type of the function (and this is the case with SFINAE). Later implementations instead ignore const when applied to function types.

The second ( T& ) has an obvious flaw that you cannot pass temporary functors.

In short, I would usually pass them on at a cost, unless I see a clear benefit in specific cases.

+19
source share

STL uses the first approach (pass by value)

Of course, standard libraries pass iterators and functors by value. They are supposed (right or wrong) to be cheap to copy, which means that if you write an iterator or functor that is expensive to copy, you may have to find a way to optimize it later.

But this only applies to those purposes for which standard libraries use functors - basically these are predicates, although there are things like std::transform . If you integrate a function, this implies some math libraries, and in this case, I suppose, you are likely to deal with functions that carry many states more often. For example, you can have a class representing n-th order polynomials, with n + 1 coefficients as non-static data elements.

In this case, the const reference might be better. When using such a functor in standard algorithms such as transform , you can wrap it in a small class that does indirect binding with a pointer to ensure that it is cheap to copy.

Taking a non-const link potentially annoys users as it stops their transmission in the time series.

+5
source share

Given the context, it is expected that F will be a "callable" (something like a free function or class that has a specific operator ())

Now, since the name of a free function cannot be an L-value, the second version is not suitable for this. The third assumes that F :: operator () will be const (but it may not be if you need to change the state of F for this) The first works with its own copy, but requires that F be copied.

None of the three are β€œuniversal,” but the first most likely works in the most common cases.

+3
source share

All Articles