2017-11-29 5:39 GMT+01:00 Lorenzo Caminiti via Boost
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;