On 30/11/2017 03:15, Peter Dimov wrote:
Lorenzo Caminiti wrote:
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.
No, moved-from objects must be valid objects. Not only can they be destroyed, they must be usable. Their state is unspecified, but invariants hold.
In general you should expect to be able to call any method which is valid on a default-constructed object, *especially* assignment operators (as it's relatively common to reassign a moved-from object). (You cannot, however, actually assume that it will return the same answers as a default-constructed object would.) It *might* also be legal to call other methods with more restrictive preconditions, but that's sort of the point -- you can't assume this either way, so actually doing so isn't really valid. The part about moved-from objects being in an unspecified state is not meant to imply that they could be "zombie" objects or otherwise invalid (because that shouldn't happen), it just means that it's allowed for the class to implement a move as a "true" move (give away storage, so now the instance is empty) or as a copy (both objects now have the same data in separate storages), or somewhere in between (such as a swap). To put it another way, if you move-assign a vector to another vector, it is perfectly legal for the source vector to not be empty afterwards. (For example, instead of a destroy-and-swap it could be implemented as a pure swap. Or even as a copy, although that's less likely with modern STLs.) This is also why this code is perfectly valid: std::vector<int> a { 1, 2, 3 }; std::vector<int> b; b = std::move(a); a.clear(); a.push_back(4); // a == { 4 }, b == { 1, 2, 3 } But omitting the call to clear() would be a bug -- it's still legal, but there's no guarantee what the contents of "a" would be at the end if you didn't explicitly clear it, so it is probably unintended. (At this point language lawyers might jump on me that vector does actually provide somewhat more specific guarantees about how move-assign behaves. But the point stands for generic types.)