Boost logo

Boost :

Subject: Re: [boost] [Bind] Interoperability of bind/mem_fn with transform_iterator
From: Samuel Debionne (debionne_at_[hidden])
Date: 2010-05-04 09:06:28


>> Daniel, thank you for your solution. But doesn't type erasure avoid some
>> optimisations to take place (inlining) ?
>
> Not necessarily. All of boost::function can be inlined. I suppose
> results may vary according to your particular compiler's optimization
> strategy, but it is not immediately clear to me that boost::function
> precludes any optimizations.
>
>> That could be a problem since the
>> function is called each time the iterator is deferred. I just did some
>> benchmarking that consists in accumulating a large range of foo id. Here are
>> the results with vc10 :

I meant to say deferenced, not defered. But I think you understood.

>> Boost.Function vs Hand Written : 9 time slower
>> Boost.MemFn vs Hand Written : 3.7 time slower
>> Boost.Function vs Boost.MemFn : 1.6 time slower
>
> A code sample that demonstrates these performance changes would be
> more informative.

I attached the code that produces these numbers. I compiled the code
with visual studio express 2010 in release mode with the default options.

The benchmark accumulates a range of number, where the numbers are
accessed through a member function (see class foo). The following
versions are compared :

1. hand written loop
2. std::accumulate with hand written member function call wrapper
3. std::accumulate with boost::mem_fn call wrapper
4. std::accumulate with boost::function call wrapper
5. std::for_each with a c0x lambda

There are a few interesting things :
- 1, 2, 5 are the fastest (about the same speed)
- using boost::mem_fn (3) really makes a difference (3 times slower)
- using boost::function (4) makes things a little bit worse (4.5 times
slower)

>> Anyway, in my opinion, using bind/mem_fn/lambda with transform_iterator is a
>> common use case. That would be great to have an option to add a default
>> constructor in those libs... or is it to risky ?
>
> Well, the downside of default constructible call wrappers is that
> certain errors are hard to detect prior to runtime; i.e. a default
> constructed call wrapper would throw a bad_function_call when invoked.
> When you use a mem_fn or bind object, you know you won't get those
> sorts of exceptions at runtime, since neither are default
> constructible. However, boost::function _is_ default constructible.
> Consequentially, it gives users a way to make that trade-off in some
> situations; i.e to sacrifice some compile time error detection in
> favor of more runtime error detection. With respect to
> transform_iterator, boost::function can bridge the conceptual gap
> between non-default constructible call wrappers and iterators, which
> are necessarily default constructible.

So, boost::function is definitely the solution. In the context of
transform_iterator, it could be interesting to "systematically" wrap
unary function objects that have no trivial constructor with
boost::function so that the resulting iterator models the expected
concept. A proposed implementation that uses the has_trivial_constructor
trait is in the attached file.
What about a warning in the usage section of the documentation of
transform_iterator ?

Samuel Debionne




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk