4 ms·
Huh, I'm sure he is correct on the intent of the spec, but it is certainly not how our team has been interpreting the allowable state of objects after a move. A
by pavon 7y ago
Huh, I'm sure he is correct on the intent of the spec, but it is certainly not how our team has been interpreting the allowable state of objects after a move. And while I understand where he is coming from in always wanting the object to meet its invariants until it is destructed, I think this approach will make code harder to reason about rather than easier.
I'm a huge proponent that classes should be fully configured on construction and should stay that way until the end of their life-cycle. I really dislike classes that are only partially configured on construction, and then you have to call other methods to complete their initialization. Then every method in the class has to have guard code to check whether the object has been fully initialized. And if you really want to code defensively users of the class also have to handle the case where an instance of that class hasn't been fully initialized, either by checking before calling a method, or by catching exceptions . It complicates things for both the user and the implementator of the class, not to mention adding computational overhead on both sides of the API.
If you require objects to be usable after they are moved from then, every object with a move constructor will either need to do extra work during the move to keep itself in a valid (but different) state, or it will need to support being in a partially configured state. In some cases it will be inexpensive to create a valid state (say change an object to point to a preallocated singleton), but in others it would completely defeat the benefit of doing a move to begin with, so you are back to supporting partially configured objects.
In the end this seems like a lot of work to keep moved objects valid, when in practice the vast majority of moved objects are implicitly moved temporaries, that are impossible to used after they are moved. And for the cases where an object was explicitly moved, the misconception that you shouldn't use an object after moving it is already well ingrained enough that it rarely happens by accident.
I can see putting in sentinels and asserts to sanity check that objects aren't being used after move (and typically do), but I'd still prefer to treat use-after-move as the bug, than complicate the normal uses of the object to support an unnecessary corner-case.
Edit: Reworded a few sentences for clarity.
- jstimpfle 7y ago> I really dislike classes that are only partially configured on construction, and then you have to call other methods to complete their initialization. What is "partially configured" after all? IMHO this dichotomy is just a headache brought to you by yours truly, OOP (or rather, syntactically enforced OOP). Personally I don't want to spend the rest of my life pondering such philosophical questions. Or dealing with all the consequences, like constructor exceptions, forced dynamic allocation because static doesn't work without initialization, etc, pp.
- gumby 7y agoC++ doesn’t believe in “partially constructed”. The real world sometime has this unfortunate event but your code is supposed to deal with it.
- pavon 7y agoTo me the question isn't a philosophical one, but a practical one. The more states an object has, the more special cases you have to handle, the more likely you are to get one wrong. The more methods an object has that can only be used when the object is in a particular state, the more likely the user of the class it to make a mistake.
- jstimpfle 7y agoSure, but states are just there, and acting like they weren't can even increase complexity. For example, RAII basically eliminates the "memory is allocated bit uninitialized" state by means of enforcing an automatic transition, at the cost of being no longer able to allocate many objects sratically.
- deleted 7y ago[deleted]