Subject: Re: [boost] [function] function wrapping with no exceptionsafetyguarantee
From: Doug Gregor (doug.gregor_at_[hidden])
Date: 2010-10-21 02:25:46
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker
> On Tue, Oct 19, 2010 at 4:56 AM, David Abrahams <dave_at_[hidden]> wrote:
>> At Tue, 19 Oct 2010 01:06:00 -0700,
>> Emil Dotchevski wrote:
>>> On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz_at_[hidden]> wrote:
>>> > "Emil Dotchevski" <emil_at_[hidden]> wrote in message
>>> > news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz_at_mail.gmail.com...
>>> >> ... at worst they'd be mad that you've used
>>> >> Boost (that's common in games, for example.)
>>> > Shall we disregard all those cases (of Boost rejection) as irrational rants
>>> > (as admittedly they often are, be it of the 'corporate policy' type or of
>>> > the Linus Torvalds type) or shall it be admitted that after all, sometimes,
>>> > they actually are based on real objections (that Boost, or parts of it, made
>>> > some not-so-happy efficiency compromising choices)...?
>>> You can't talk about Boost efficiency in general. As difficult as it
>>> is to pull apart, Boost contains individual components. Are we talking
>>> about the efficiency of Boost Function then? I'm sure if someone
>>> manages to speed it up, many people on this mailing list (not to
>>> mention the folks who are implementing std::function) would be very
>>> interested to see how it can be done.
>> I think we already know one way: we can easily get rid of the separate
>> empty() check by making sure empty boost::functions all invoke a
>> function that throws bad_function_call.
> After taking a closer look at this idea, I don't think it is possible
> to do this without either changing boost::function's semantics or
> incurring other runtime expenses.
> First of all, boost::function can be in an empty state for two
> reasons: either it has not been assigned a target function or there
> has been a problem with the internal target management system. Both of
> these conditions are tested simultaneously by the current empty check
> in operator(). If we get rid of the empty check, we will no longer be
> checking that the target management system is in working order and
> able to dispatch function calls (or more specifically, that
> boost::function's internal vtable pointer is non-null). If the target
> management system is not in an usable state, then we cannot dispatch a
> default "empty" function that throws bad_function_call. So, if we get
> rid of the current empty check but retain the current target
> management system, we open the possibility that boost::function could
> be in an empty state but would not throw when invoked, which would be
> a change in semantics.
The latter "state" isn't a real state; it only exists if there's a bug
in boost::function, and we don't design around bugs.
> Alternatively, we could rewrite the target management mechanisms to
> ensure that boost::function always has a usable vtable object. This
> implies providing a defualt "empty" vtable, which boost::function's
> vtable pointer could refer to when in an empty state, so that the
> pointer is always non-null.
Yes, that's the implementation technique that has been discussed a
number of times.
> There would need to be a different "empty"
> vtable each time boost::function is instantiated with a different call
> signature, so that the "empty" vtable can be used seamlessly by
> operator() for any call signature.
One per boost::function signature, yes.
> These "empty" vtable objects could
> not be allocated on demand, since they would need to be available to
> boost::function even in the event of heap allocation failures.
They would go into the data segment, as the current vtables do.
> adding "empty" vtable objects would increase the space requirements of
> boost::function; each template instantiation would need two
> corresponding vtable objects, one for actual targets and one as a
> fallback that throws bad_function_call. (The "empty" vtable objects
> could be stored statically, but static storage is also a very precious
> resource on many platforms.) Not all users would appreciate this
> trade-off; i.e. an increase in the space overhead for a small decrease
> in time overhead (with compiler optimization the time savings are
> minuscule, in my experience).
Without quantifying the trade-off, we don't know which way is better.
In any case, this issue is fairly easy to settle; it just takes
effort. Someone implements this alternative scheme and determines the
cost/benefit in space and time, and with any luck the choice is