|
Boost : |
From: Pavol Droba (droba_at_[hidden])
Date: 2004-07-15 02:32:10
On Wed, Jul 14, 2004 at 07:55:23PM -0500, David B. Held wrote:
> Pavol Droba wrote:
> >[...]
> >I have put some info into the docs, but I'm not sure if it is
> > correct and sufficient. Could some of you, that had lead the
> > discussion about this topic (namely David Abrahams or David B.
> > Held) check it out and tell me your opinion?
> > [...]
>
> Looks fine to me. However, instead of saying that the library makes
> assumptions about the exception safety of template and function
> arguments, I would say that providing the basic guarantee is a
> precondition for using the library. Also, I think it would be helpful
> to have a table of exactly which functions give a stronger guarantee,
> unless to_lower_copy() is the only such function, in which case you
> should just mention that in the original note. Note that it is
> operations which give exception safety guarantees, not types. For a
> given type, there may be functions (member or free) which offer the
> basic, strong or nothrow guarantee
You are correct. Exception guarantee should talk about the operations.
Thats was what I originaly wanted to say ... but somehow it was lost
in the translation.
As for the table. It would be probably quite long. About 1/3-1/2 of functions
are candidates for strong exception guarantie. There is not as each of them.
>
> Technically, you want to look at which member/user-defined functions
> of the argument types get called, and require those to provide the basic
> guarantee. Really, all functions should provide the basic guarantee, so
> this should really go without saying, but it's better to say it to
> remind users. This is probably how I would word that section:
>
> Exception Safety
>
> The library requires that all operations on types used as template or
> function arguments provide the basic guarantee. In turn, all
> functions and algorithms in this library, except where stated
> otherwise, will provide the basic guarantee.
>
This seems reasonables. I my version I came from assuption, that user
is not forced to provide any guarantee, on the other hand, she will
not get more then she provides. But saying that as an explicit
requirement is probably more consisten
> Now, here is where it gets tricky. You mention "const operations",
> which should probably read "pure operations", possibly with a note
> specifying that "pure" means "without side effects".
Well difference between "pure" and "const" operations as I see it,
is that const operations do not modify the state of the object, while
pure operations do not modify global state as well.
I wanted to close this gasp by requiring that const operations provide
strong guarantee for the global state.
Pure operations have strong guarantee by desing, but using this term
will enforce me to specify which operations must be pure.
And now I see, that I will need another type of operations to consider.
Those that modify the internal state of an object, but do not touch the global state.
So what I realy need it to specify is , that operations that are not closed
to the object (i.e. they modify global state) have strong exception guarantie.
Such a guarantee would allow me to use a local variable of a given type
without needing to worry, that it will break the guarantie of the whole
function.
Is this ok?
How would you name such a property?
> But really, in
> order to provide the strong guarantee, you need to state exactly which
> user functions need to be pure. Let's analyze to_lower_copy() to see
> what we should say about it:
>
> template< typename ContainerT >
> inline ContainerT to_lower_copy(
> const ContainerT& Input,
> const std::locale& Loc=std::locale() )
> {
> ContainerT Output;
> std::transform(
> string_algo::begin(Input),
> string_algo::end(Input),
> std::back_inserter<ContainerT>( Output ),
> string_algo::detail::to_lowerF(Loc) );
>
> return Output;
> }
>
> Now, let's look at what functions are being called. First,
> std::locale() is called, but I'm pretty sure we can assume that does not
> modify global state. Thus, it is a pure function. Next, ContainerT()
> is called. If it provides the basic guarantee but modifies global state
> before throwing, then this function will not provide the strong
> guarantee.
I see that I have followed wrong assumption here. I forgot about the global state.
I have assumed, that when a ContainerT() behaves nice (i.e have basic guarantee)
and it is only a local object, that w.t.r to caller of the to_lower_copy
it provides strong gurantie.
Again you are right, I have to explicitly ask for preservation of global state.
> Next, string_algo::begin() and ::end() are called, which I
> assume are pure functions. Since std::back_inserter() is called on
> local data, it is pure with respect to to_lower_copy(). Since Loc is
> passed by const&, we assume that string_algo::detail::to_lowerF(Loc)
> does not modify Loc nor global state. Thus, it too is pure w.r.t.
> to_lower_copy(). Finally, since std::transform() is called on local or
> const data, it too is pure w.r.t. to_lower_copy(). So this function can
> give the strong guarantee if it has the signature
>
> { pure, strong, pure* }
>
> Where the first one is std::locale(), the second is ContainerT(), and
> the rest is std::transform et al. So what we really mean is that
> to_lower_copy() gives the strong guarantee when ContainerT's default
> constructor gives the strong guarantee. Note that none of the other
> c'tors of ContainerT need give any special guarantees. So be careful
> not to overspecify your client requirements for exception safety.
> Exception safety is a property of operations, not types. Hope that helps.
>
Thanks for help. I see, that I'm on the right track, but there is still some
work to be done.
Regards,
Pavol
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk