Boost logo

Boost :

Subject: Re: [boost] [type_erasure] Review started (July 18-27, 2012)
From: Chapman, Alec (archapm_at_[hidden])
Date: 2012-08-03 21:36:33

On 08/02/2012 8:23 AM, Steven Watanabe wrote:
> Use the any(any<Concept2, T2>, binding<Concept>) constructor.
> It allows you to convert the vtable once, and re-use it for all the anys.

This constructor doesn't seem to work with gcc 4.7.0 because the copy constructor for binding doesn't exist:

typedef mpl::vector<te::copy_constructible<>, te::addable<>, te::incrementable<>> add_inc;
typedef mpl::vector<te::copy_constructible<>, te::incrementable<>> inc;
te::any<add_inc> x(3);
te::binding<inc> binding(te::binding_of(x), mpl::map<mpl::pair<te::_self, te::_self>>());
te::any<inc> y(x, binding);

boost/type_erasure/any.hpp:444:9: error: use of deleted function âboost::type_erasure::binding<boost::mpl::vector<boost::type_erasure::copy_constructible<>, boost::type_erasure::incrementable<> > >::binding(const boost::type_erasure::binding<boost::mpl::vector<boost::type_erasure::copy_constructible<>, boost::type_erasure::incrementable<> > >&)â

So I switched to VC10 for my benchmarks.
This time I ran five tests summing a vector of anys by:
1) using the any elements directly.
2) up-converting using the default constructor (and capturing by reference)
3) up-converting using a single binding object
4) up-converting, looking up the binding in a map
5) up-converting, looking up the binding in a map that directly compares addresses of type_info objects

The results were:
1) 0.73 s (no conversion)
2) 41.19 s (default conversion)
3) 3.80 s (single binding)
4) 31.52 s (slow, correct lookup)
5) 4.92 s (fast lookup)

Using std::type_info::before for map comparisons adds a lot of overhead (4 vs 5). In practice I could get away with just comparing addresses and storing multiple copies.

For me the relevant comparison is test 5 vs test 1, so conversion is still 7x slower than not converting (shared_ptr copying?). Recall from my previous test that using static vtables for conversions only added 30% overhead.

My impression is that static vtables would be a better default behavior, possibly with the option for the user to specify a dynamic binding if they really need to optimize for many repeated function calls. The current behavior has huge overhead by default. Avoiding this requires the user to write a decent amount of code that is dangerous in terms of introducing undefined behavior (if the wrong binding is applied), or creating its own performance problems (the choice of map lookup), and even then the overhead still appears to be very large. Specifying a binding is essentially like casting from a void*. I like that this capability is provided, but I think the library should strive to keep the number of cases where it is required in user code to a minimum.

> > I propose an overloaded constructor that signals that the underlying
> > object
> should be held by reference but copied when the any object is copied:
> >
> > int i = 0;
> > any<requirements> a(i, capture_reference); any<requirements> b(a);
> > ++a; // i == 1
> > ++b; // i == 1 still, any_cast<int>(b) == 2
> >
> > This has worked well in my own code and should be easy to implement.
> > I think
> this would also avoid the bug mentioned at the bottom of the
> references page of the documentation.
> >
> I don't think this is a good idea, as it would require an extra flag
> whether it's needed or not.

Steven, do you have any thoughts on my previous reply to this? I have implemented this without any cost.

I still feel that the features I've commented on are at too much of an experimental stage and that better solutions exist. My experience has been that erased types need to behave as similarly as possible to their underlying types, especially if they are to be used in generic code. I don't see the advantages of forcing the user to deal with what is essentially a parallel version of the type system for references when there is IMHO a more natural approach that carries no cost and is more generally useable. See my comments above as well. Conversions become less useful if they can't be used naturally like other types.

Boost list run by bdawes at, gregod at, cpdaniel at, john at