Question

I have just read the classic book "Effective C++, 3rd Edition", and in item 20 the author concludes that built-in types, STL iterators and function object types are more appropriate for pass-by-value. I could well understand the reason for built-in and iterators types, but why should the function object be pass-by-value, as we know it is class-type anyway?

Was it helpful?

Solution

In a typical case, a function object will have little or (more often) no persistent state. In such a case, passing by value may no require actually passing anything at all -- the "value" that's passed is basically little or nothing more than a placeholder for "this is the object".

Given the small amount of code in many function objects, that leads to a further optimization: it's often fairly easy for the compiler to expand the code for the function object inline, so no parameters get passed, and no function call is involved at all.

A compiler may be able to do the same when you pass a pointer or reference instead, but it's not quite as easy -- a lot more common that you'll end up with an object being created, its address passed, and then the function call operator for that object being invoked via that pointer.

Edit: It's probably also worth mentioning that the same applies to lambdas, since they're really just function objects in disguise. You don't know the name of the class, but they create a class in the immediately surrounding scope that overloads the function call operator, which is what gets invoked when you "call" the lambda. [Thanks @Mark Garcia.]

OTHER TIPS

The #1 reason to pass function objects by value is because the standard library requires that function objects you pass to its algorithms be copyable. C++11 §25.1/10:

[ Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as reference_wrapper<T> (20.8.3), or some equivalent solution. —end note ]

The other answers do a great job of explaining the rationale.

From Effective STL (since you seems to like Scott Meyers) item 38 Design functor classes for pass-by-value.

"In both C and C++ function pointers are passed by value. STL Function objects are modeled after function pointers, so the convention in the STL is that function objects, too, are passed by value when passed to and from functions."

This has some benefits and some implications, like @Jerry Coffin said, the compiler can make some optimizations like inlining the code to avoid function calls (You have to mark your functor as inline). A good example of this case is the qsort vs std::sort performance comparison, where std::sort using inline functors outperform qsort by a lot, you can find more information on this on Effective STL where it is discussed extensively and mentioned in several chapters.

This also has several implications too, since function objects are passed and returned by value, you have to make sure your object have a well defined copy mechanisms, are small in size (otherwise it could get expensive), and are monomorphic (since passing polymorphic objects by value may result in object slicing).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top