Subject: Re: [boost] [function] function wrapping with no exceptionsafetyguarantee
From: David Abrahams (dave_at_[hidden])
Date: 2010-10-12 16:15:53
At Tue, 12 Oct 2010 15:14:58 -0400,
Daniel Walker wrote:
> On Tue, Oct 12, 2010 at 2:09 PM, David Abrahams <dave_at_[hidden]> wrote:
> > At Tue, 12 Oct 2010 13:48:37 -0400,
> > Daniel Walker wrote:
> >> Also, swapping out throw_bad_function call does not directly address
> >> the boost::function/Boost.Exception coupling issue. If
> >> boost::function is going to offer a strong exception safety
> >> guarantee, then I believe Boost.Exception is the best way to
> >> implement that guarantee, no matter how boost::function gets around
> >> to calling boost::throw_exception. (I also think boost::function
> >> should continue to offer the strong guarantee.)
> > Which operation of boost::function are you talking about, that offers
> > the strong guarantee? Â And how can Boost.Exception be a way to achieve
> > the strong guarantee?
> operator() offers a strong guarantee in that it either calls the
> target or calls boost::throw_exception.
That isn't the strong guarantee; it's just part of the class's
non-exceptional semantics. The strong guarantee has to do with what
happens *when* an exception is thrown. You should stop using the term
that way unless you want to confuse everybody.
> I don't mean Boost.Exception is used to "achieve" the guarantee, but
> to implement it; i.e. in the case where the wrapper is empty,
> boost::throw_excpetion can be used instead of a throw
> statement. This is preferable because it allows the exception to be
> reported with or without RTTI.
> >> But some users are asking for a function object wrapper that is not
> >> coupled with Boost.Exception.
> > Why?
> Some users who do not use RTTI (e.g. on some embedded system),
I think that's irrelevant. Actually RTTI and EH are orthogonal in
principle, though they use similar mechanisms and some compiler
vendors may tie them together. In any case Boost.Exception can be
configured not to use it.
> do not want to take the time to configure Boost.Exception for their
> platform, and without configuring Boost.Exception, they get
> unexpected link errors, because boost::throw_exception is undefined.
If users are going to use a subset of C++, they should not be too
surprised that they have to add a -D option to their command-line to
keep everything linking. Avoiding that is certainly not worth the
cost of supporting a parallel copy of boost::function.
> >> boost::function always provides a strong exception safety guarantee.
> >> Specifically, if its preconditions are not met, it calls
> >> boost::throw_exception.
> > That's not strong exception-safety. Â That's throwing an exception
> > where an assert belongs. :-(
> I'm using the following definition of strong exception safety.
> "The strong guarantee: that the operation has either completed
> successfully or thrown an exception, leaving the program state exactly
> as it was before the operation started."
Yes, I invented the term and wrote that definition, but no, you're not
using it properly.
All constructors with no side-effects offer the strong guarantee, by
the way. So asserting that a constructor offers the strong guarantee
is not very meaningful once you know that the constructor's semantics
are side-effect free.
> I suppose there is a nuance here in that the target function could
> throw, so more formally we could say boost::function has strong
> exception safety if the target function has strong exception safety.
Sorry, but that makes no sense. Classes don't have strong
exception-safety. Only operations do.
> Here the definition of the phrase "thrown an exception" depends on
> the definition of boost::throw_exception, which is user
I don't think you can redefine the phrase âthrows an exceptionâ to
mean something that might not throw an exception, and still communicate
> >> This is true whether or not the system has
> >> RTTI. This is great for some users, but others have asked for a
> >> function object wrapper that does not call boost::throw_exception. A
> >> simple way to meet this requirement is to provide a function object
> >> wrapper that is exception unsafe, like a typical function pointer for
> >> example, and that is what unsafe_function does.
> > IMO a better way to do it would be to make a function object that
> > has no empty state.
> I'm amenable to that. What would you call it?
> >> > Â I think if you're looking to supply motivation for unsafe_function,
> >> > you'll need to describe the goal differently. ;-)
> >> How about this. Typically, function pointers have no RTTI dependency
> >> (and no dependency on Boost.Exception) and are exception unsafe.
> > In what sense are function pointers exception-unsafe?!
> Their behavior is undefined when they are null; i.e. when they are
> invoked they offer neither a basic, strong nor nothrow guarantee.
That is *not* exception-unsafe! There are documented preconditions on
the function call operator, and you must satisfy them or all bets are
off. Almost every operation in std:: has such conditions here or
there. That doesn't make them exception-unsafe. Exception-unsafe
means that *when* an exception is thrown, invariants are violated (or
> >> unsafe_function is a function object wrapper that behaves more like
> >> a function pointer with respect to exception safety.
> > I am beginning to think you have a different definition of exception
> > safety from the rest of the world.
> Well, it's important to use similar definitions. I'm trying to stick
> to the definition above. How can I do this better?
Other than studying the definitions and taking them literally, I don't
know what to suggest.
-- Dave Abrahams BoostPro Computing http://www.boostpro.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk