Compare generic integration functions:
template <class F> double integrate(F integrand);
with
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 (pass by value), does it mean it's the most universal one?
Function objects usually should be small so I don't think that passing them by value will suffer from performance noticably (compare it to the work the function does in its body). If you pass by value, you can also gain from code analysis, because a by value parameter is local to the function and the optimizer may tell when and when not a load from a data member of the functor can be omitted.
If the functor is stateless, passing it as argument implies no cost at all - the padding byte that the functor takes doesn't have to have any particular value (in the Itanium Abi used by GCC at least). When using references, you always have to pass an address.
The last one (const T&
) has the drawback that in C++03 that doesn't work for raw functions, because in C++03 the program is ill-formed if you try to apply const
to a function type (and is an SFINAE case). More recent implementations instead ignore const
when applied on function types.
The second one (T&
) has the obvious drawback that you cannot pass temporary functors.
Long story short, I would generally pass them by value, unless I see a clear benefit in concrete cases.
STL uses the first approach (pass by value)
Sure, the standard libraries pass iterators and functors by value. They are assumed (rightly or wrongly) to be cheap to copy, and this means that if you write an iterator or a functor that is expensive to copy, you might have to find a way to optimize that later.
But that is just for the purposes for which the standard libraries use functors - mostly they're predicates, although there are also things like std::transform
. If you're integrating a function, that suggests some kind of mathematics libraries, in which case I suppose you might be much more likely to deal with functions that carry a lot of state. You could for example have a class representing nth order polynomials, with n+1 coefficients as non-static data members.
In that case, a const reference might be better. When using such a functor in standard algorithms like transform
, you might wrap it in a little class that performs indirection through a pointer, to ensure that it remains cheap to copy.
Taking a non-const reference is potentially annoying to users, since it stops them passing in temporaries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With