|
Boost : |
Subject: Re: [boost] [contract] move operations and class invariants
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-11-29 08:29:41
2017-11-29 5:39 GMT+01:00 Lorenzo Caminiti via Boost <boost_at_[hidden]>
:
> Hello all,
>
> This is not really a question about Boost.Contract, but more a
> question on how contract programming interacts with C++ move
> operations.
>
> C++ requires that moved-from objects can still be destructed. Because
> contract programming requires class invariants to hold at destructor
> entry, it follows that moved-from objects must still satisfy class
> invariants.
>
> That sounds restrictive... and it might force the class invariants to
> be empty. For example, for vector a class invariant is size() <=
> capacity(). Should that sill hold after the vector has been moved?
> That means I can still call size() and capacity() on a moved-from
> object, which might not be the case.
>
> If some sort of moved() function could be called on a moved-from
> object, the invariants could be programmed as follow to work around
> this issue:
>
> class vector {
> void invariant() cont {
> if(!moved()) BOOST_CONTRACT_ASSERT(size() <= capacity());
> ... // Only invariants that are truly needed to execute the
> destructor.
> }
>
> bool moved() const;
>
> public:
> vector(vector&& other) {
> boost::contract::check c = boost::contract::constructor(this)
> .postcondition([&] {
> BOOST_CONTRACT_ASSERT(!moved());
> BOOST_CONTRACT_ASSERT(other.moved());
> })
> ;
> ...
> }
>
> ...
> };
>
> I'm not really sure... What do you think? Do you know if this topic
> "C++ move & class invariants" has already been discussed somewhere?
>
Sort of. I think that there is a consensus there: if you allow the
*special* moved-from state, or "zombie" state (occasionally, but not
necessarily, equivalent to default-constructed state), you cannot have
strong invariants in your class. Now your invariants will have to be
"either in zombie state or the strong invariant holds".
Some mention of it in the blog post:
https://akrzemi1.wordpress.com/2016/04/07/sessions-and-object-lifetimes/
This is one tiny aspect where C++11 move semantics made the language a bit
worse compared to C++98. This can be somewhat mitigated in C++17, where you
can return by value non-moveable types. No moves - no weak invariant
problems.
Proper fix could only be achieved with "destructive move", but I do not
know if it is doable in C++.
Regards,
&rzej;
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk