Boost logo

Boost :

Subject: Re: [boost] [contract] Strong exception safety guarantees
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2016-07-15 13:37:30


2016-07-15 19:22 GMT+02:00 Lorenzo Caminiti <lorcaminiti_at_[hidden]>:

> On Fri, Jul 15, 2016 at 12:35 AM, Andrzej Krzemienski
> <akrzemi1_at_[hidden]> wrote:
> > 2016-07-15 6:04 GMT+02:00 Lorenzo Caminiti <lorcaminiti_at_[hidden]>:
> >
> >> I've been considering adding a .except(...) construct to
> >> Boost.Contract that will allow to specify conditions to check at
> >> function exit but when the function body throws (in contrast to
> >> postconditions that are checked at function exit but only when the
> >> function body does not throw).
> >>
> >> I think .except(...) could be used to assert strong exception safety
> >> guarantees... (note that class invariants are already checked at exit
> >> of public functions and also when the public function bodies throw,
> >> but invariants are suited to assert only basic, and not strong,
> >> exception safety guarantees).
> >
> > How would you express the strong guarantee on std::vector::push_back?
>
> vector::push_back exception safety:
>
> ``If no reallocations happen, there are no changes in the container in
> case of exception (strong guarantee).
> If a reallocation happens, the strong guarantee is also given if the
> type of the elements is either copyable or no-throw moveable.
> Otherwise, the container is guaranteed to end in a valid state (basic
> guarantee).
> If allocator_traits::construct is not supported with val as argument,
> it causes undefined behavior.''
>
> http://www.cplusplus.com/reference/vector/vector/push_back/
>
> Hmm... so assuming the allocator API can be augmented with an
> allocations() const query that returns the number of allocations done
> so far, and that operator== can be used to check if the vector has not
> changed, maybe something like this:
>
> template<typename T>
> void vector<T>::push_back(T const& value) {
> boost::contract::old_ptr<vector<T> > old_me =
> BOOST_CONTRACT_OLDOF(*this);
> boost::contract::old_ptr<unsigned> old_allocations =
> BOOST_CONTRACT_OLDOF(get_allocator().allocations());
> boost::contract::guard c = boost::contract::public_function(this)
> ... // Preconditions and postconditions.
> .except([&] {
> if(
> get_allocator().allocations() == *old_allocations ||
> is_copyable<T>::value ||
> is_nothrow_movable<T>::value
> ) BOOST_CONTRACT_ASSERT(*this == *old_me);
> // Otherwise, just basic guarantees as asserted by the
> class invariants.
> })
> ;
>
> ... // Body implementation.
> }
>
> I'm not 100% sure... what do you think?
>

It bothers me that I have to copy the entire vector upon each push_back.
Because OLDOF stuff must do a copy, right? I do not think I could afford
that; even in debug builds.

Regards,
&rzej;


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