Le 2017-11-29 05:39, Lorenzo Caminiti via Boost a écrit :
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.
This is not only about destructors, but more generally about reusing moved-from objects.
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 it can’t hold, that should be part of the contract. IMHO moving-from can result in two situations : 1) reverting back to an empty state 2) going to an invalid state The bad thing with 2) is that currently you have no way to compile-time check it, and it will lead to crashes. 1) is safer, but has problems with RAII, since the object no longer hold any resource.
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:
I'm not really sure... What do you think? Do you know if this topic "C++ move & class invariants" has already been discussed somewhere?
I’m not aware of any litterature on this. At first glance, i’ll separate two things : - value types (such as std::vector), for which move semantic is mainly a performance matter. For those types, 1) (empty state) makes a lot of sense. - entity types (which holds resource), for which move semantic is really an ownership transfer. For those types, 1) doesn’t make a lot of sense, and 2) may lead to hard to debug crashes. In the current state of the language, I’d rather make these types not movable, and use unique_ptr to transfer ownership. Regards, Julien