Subject: Re: [boost] [function] function wrapping with no exceptionsafetyguarantee
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2010-10-21 19:05:12


On Thu, Oct 21, 2010 at 6:13 PM, Edward Diener <eldiener_at_[hidden]> wrote:
> On 10/21/2010 6:05 PM, Daniel Walker wrote:
>>
>> On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor<doug.gregor_at_[hidden]>
>>  wrote:
>>>
>>> On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker
>>> <daniel.j.walker_at_[hidden]>  wrote:
>>>>
>>>> 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.
>>
>> Right. I don't mean the management system has a bug, I mean that it
>> has encountered a problem, for example, cloning the target. So,
>> boost::function could be empty because it has never been assigned a
>> target or because the most recent attempt to assign a target failed...
>> or because it was cleared by the user calling clear(). Are those all
>> of the scenarios that can lead to an empty boost::function?
>
> I don't mean to question the design of boost::function but wouldn't the
> inability of cloning a target, or assign a target, be a problem which should
> lead to an exception being thrown ?

Right, but suppose boost::function was instantiated outside of the try
block where the assignment fails. Then after the exception is thrown
and handled, the boost::function object could still be used.

But actually, I just noticed that, even though the portable function
wrappers are empty after an assignment failure, boost::function is not
actually cleared. So, in fact, a failed assignment is NOT a scenario
that leads to an empty state, as I first thought. This is probably an
oversight/bug in the portable wrappers, right?

>
> I would assume that boost::function not having a target would normally only
> occur if no target had been set or if the user removed a target which had
> been set.

Right, and indeed, this appears to be the case... unless there's some
other scenario we overlooked...

Daniel Walker