Say I have a function like this:
void someFunction(const ExpensiveObjectToCopy&);
If I make a boost::function out if it, that function will store its own cloned copy of the object in its closure:
boost::function<void()> f = boost::bind(someFunction, x); // <-- f saves a copy of x
Now if I start passing f around, will the boost::function copy constructor copy that object again each time, or does each function share the same closure? (i.e. like this)
boost::function<void()> f2 = f;
callSomeFunction(f);
etc.
From what I can find (Judging from a cursory reading of the not exactly simple source and some experiments) it will copy the cloned object each time. It might be unnecessary in case of the function taking it’s argument by const &, but in general the object might be mutated by the function. If the object is expensive to copy, wouldn’t it make sense to capture it by reference (
boost::reforboost::crefcome to mind) or, if the original object doesn’t exist at the point of invocation, capture aboost::shared_ptrand write a adapter method, which unpacks the smartpointer and callssomeFunction?Edit: From experimentation not only will it copy construct that object whenever the
boost::functionis copied, but it will also copy several times insideboost::bind. I tested using the following code using boost 1.45 under mingw 32 with gcc 4.6 and -O2 ( and -std=c++0x):The resulting output is as followed:
So the copy constructor was called for the creation of f2 once and 11 times for the binding and assignment to f1. Since the first object is created on the stack and the addresses of the copies are very close to that and slightly increasing, it seems that the binding process goes through a lot of functions, which the compiler doesn’t inline in this case and which each pass the object along by value. Using just
boost::bindwithout saving the result anywhere:So five copies just to bind the object. So I would generaly avoid capturing anything which has at least moderate copy costs per value in any even remotely performance sensitive parts of the code. In comparison gccs
std::tr1::bindandstd::bindperform much better (in conjunction with std::tr1::function / std::function) (code is basically identical to the first testcode, just substituteboost::withstd::tr1::respectivelystd:::I assume
std::bindeither passes by const ref for internal invocations, or is written in a way which is more friendly to gccs inliner to inline some in and eliminate redundant copy constructors.tr1::bindstill gets better optimized thenboost::bind, but still far from optimal.Of course as always with such a kind of tests YMMV with different compile flags/compilers