
On Sun, Nov 7, 2010 at 4:14 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote: On Sat, Nov 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
void throw_bad_function_call() { throw bad_function_call(); }
function<void()> f( &throw_bad_function_call );
doesn't take up any additional space per type, unless of course the > program never stores a function pointer into function<>.
This is a special case: all targets are function pointers of the same type, right?
No. It's enough for one of them to be.
Oh, I see, if the user ever assigns a function pointer target, then you can reuse the vtable from the empty target. OK, that's a reasonable optimization, but it doesn't decrease the upper bound on space overhead, which is reached when no user-assigned target has the same type as the empty target.
On my system, the text segment grows by up to 14% when boost::function( &throw_bad_function_call ) is used for empty wrappers.
It's very uncommon for real code to not already contain the necessary instantiations or the equivalent of throw_bad_function_call itself.
Actually, I just saw a real world example the other day. The benchmark that Domagoj suggested (the Boost.Signal benchmark code from Christophe Prud'homme) does not use function pointers and would not benefit from your suggestion. So, I don't think we can assume it is uncommon for boost::function to be used without function pointers. (On a personal note, the first time I started using boost::function was to store the return value of boost::bind, so none of my old code assigned boost::function with a function pointer. I imagine there are others who came down the same road as me.)
As soon as you put a function pointer into boost::function, you ought to get the instantiations; and as soon as you call it, you ought to get code that throws bad_function_call. Or I may be missing something.
No, you're correct with respect to the text segment. You get all the instantiations from the first function pointer target. However, if the user does not assign a function pointer, then the increased text segment overhead from using an "empty" function pointer approaches 14% on my system. Again, all of this just further illustrates that the costs and benefits of the static empty scheme vary according to circumstances. Some users will experience little cost and/or little benefit. Those who decide that the benefit merits the cost can choose to use the alternative scheme. But I see no reason to increase the costs for any user when there is no guarantee that there will be some benefit. The benchmarks demonstrate that removing the null pointer check from operator() does not always yield a significant time savings. Daniel Walker