Boost logo

Boost :

Subject: Re: [boost] [function] function wrapping and exception safety recap
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2010-10-12 14:08:56


On Mon, Oct 11, 2010 at 4:13 PM, Emil Dotchevski
<emil_at_[hidden]> wrote:
> On Mon, Oct 11, 2010 at 12:57 PM, Daniel Walker
> <daniel.j.walker_at_[hidden]> wrote:
>> On Mon, Oct 11, 2010 at 3:20 PM, Emil Dotchevski
>> <emil_at_[hidden]> wrote:
>>> On Mon, Oct 11, 2010 at 11:53 AM, Daniel Walker
>>> <daniel.j.walker_at_[hidden]> wrote:
>>>> On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker
>>>> <daniel.j.walker_at_[hidden]> wrote:
>>>>> On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski
>>>>> <emil_at_[hidden]> wrote:
>>>>>> On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker
>>>>>> <daniel.j.walker_at_[hidden]> wrote:
>>>>>>> On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin_at_[hidden]> wrote:
>>>>>>>> On 11 October 2010 00:01, Emil Dotchevski <emil_at_[hidden]> wrote:
>>>>>>>>> On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker
>>>>>>>>> <daniel.j.walker_at_[hidden]> wrote:
>>>>>>>>>> Finally, there have been suggestions to alter boost::function's
>>>>>>>>>> exception safety guarantee directly through either policies or
>>>>>>>>>> constructor options.
>>>>>>>>>
>>>>>>>>> We used to have an Allocator parameter to the boost::function template
>>>>>>>>> and it was removed (just in time for this change to also be reflected
>>>>>>>>> in C++0x) to reduce coupling.
>>>>>>>>
>>>>>>>> So what exactly is the proposed behavior if the function object cannot
>>>>>>>> fit in the small object optimization space of unsafe_function and the
>>>>>>>> allocation fails?
>>>>>>>
>>>>>>> As proposed, unsafe_function has the same semantics as boost::function
>>>>>>> with one (and only one) exception: the behavior of operator() is
>>>>>>> undefined when it has no target.
>>>>>>
>>>>>> If that was the only motivation, you could just disable exception
>>>>>> handling, and then define:
>>>>>>
>>>>>> namespace boost
>>>>>> {
>>>>>>  void throw_exception( std::exception const & )
>>>>>>  {
>>>>>>    assert(0);
>>>>>>  }
>>>>>> }
>>>>>>
>>>>>
>>>>> Correct. But users have complained about this, which is exactly the
>>>>> motivation for unsafe_function. It works out-of-the-box in RTTI-free
>>>>> environments with no dependency on boost::throw_exception. It's a
>>>>> simple problem really.
>>>>
>>>> P.S. Sorry I spoke to soon. That's not exactly correct. A user could
>>>> do what you describe, but boost::function could not, since that would
>>>> change its exception safety guarantee; i.e. it would no longer throw
>>>> (or call a user definable function) when it had no target.
>>>
>>> This is not exception safety issue, it is a choice between defined and
>>> undefined behavior.
>>
>> A strong exception safety guarantee is a defined behavior.
>
> Any behavior fits "undefined behavior". Like I said, if someone wants
> undefined behavior, they can't be against any particular behavior,
> including throwing an exception.
>
>> Another group of users, would like a function wrapper without coupling
>> Boost.Exception, and indeed, without an exception safety guarantee.
>> unsafe_function address the demands of this second group of users.
>
> What is the problem with adding a constructor such that you could say:
>
> boost::function<T>(f,std::nothrow)
>
> This way, I'm pretty sure that as long a program only instantiates the
> nothrow constructors, the resulting executable won't depend on
> boost::throw_exception.

True, that can be done, but boost::function is still default
constructible and can still be cleared through assigning 0. So, you
end up back to the exception safety question of how operator() behaves
when the wrapper is empty. As you suggest, you could have the behavior
depend on how it was constructed, so sometimes boost::function has a
strong exception guarantee, sometimes it has a nothrow guarantee (and
presumably, it's a no-op when empty). This is a matter of personal
preference. To me it's simpler to say that boost::function always has
a strong exception safety guarantee, as is currently the case, and
other function object wrappers could be added to offer other
guarantees, including no guarantee, like a plain vanilla function
pointer, which is what unsafe_function does. Under this scheme, we
could also add nothrow_function that would offer a nothrow guarantee,
and semantically, it would be a no-op when empty, per your example.

Daniel Walker


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