4 ms·
It’s nice to make invalid states unrepresentable. Unfortunately, you can’t do that in C++ if you have a move constructor. C++ moves have to leave the source o
by comex 2y ago
It’s nice to make invalid states unrepresentable. Unfortunately, you can’t do that in C++ if you have a move constructor. C++ moves have to leave the source object in a valid state, since the object can still be accessed afterwards and will still have its destructor run. But unless your move is really just a copy, that state has to be some kind of default, or at least semantically meaningless. And if a valid but semantically meaningless state exists, arguably you might as well use it for the default constructor too.
- deleted 2y ago[deleted]
- masklinn 2y agoI don’t think that argument holds much water. A moved-from object needs to be in a valid state because the destructor will still run, and so that needs to succeed (and not UB). Nobody ever says the moved-from state had to be useful or recoverable from. Alternatively, you can remove support for moving. That way the moved-from issue disappears.
- nemetroid 2y agoThe standard library types are guaranteed to be in a useful state after being moved from (the term "valid state" is used for this). Of course, that doesn't mean that your own types have to, but the C++ Core Guidelines suggest doing so [1]. 1: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-move-semantic https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines...
- forrestthewoods 2y agoI'm not sure I would say that "valid" and "useful" are the same. Things that must be safe after moving: destructing, assigning. No other operation need make sense. It sucks that C++ can't enforce "don't use struct after moving". It's definitely a wart, of which C++ has no shortage. But you can still get away with no default constructor and not having to sprinkle a kajillion "isUseful" checks around your codebase. Code can assume the struct is useful. The case where it's not is rare and probably won't ever come up. Such is life when writing C++!
- nemetroid 2y ago> I'm not sure I would say that "valid" and "useful" are the same. In standardese, they are: an object in a "valid but unspecified state" requires "that the object’s invariants are met and operations on the object behave as specified for its type"[1]. In other words, any operation without preconditions may be performed. > Things that must be safe after moving: destructing, assigning. No other operation need make sense. That's not accurate for standard library types: moved-from objects must be in a "valid but unspecified state"[2]. 1: C++23 working draft, 3.66 valid but unspecified state [defns.valid] 2: C++23 working draft, 16.4.6.15 Moved-from state of library types [lib.types.movedfrom]
- dataflow 2y agoYou make it seem like such a terrible thing, but a valueless state is the only exception to "you can make invalid states unrepresentable", and a pretty useful one given the rest of the language. And it's not one that you have to worry about in practice because nobody will intentionally abuse this, and your compiler/linter will diagnose accidental reuses. Guarding against it anyway is like guarding against someone passing a destroyed object to you - it just doesn't make sense to.
- gumby 2y ago> Guarding against it anyway is like guarding against someone passing a destroyed object to you - it just doesn't make sense to. It doesn’t make sense to do so intentionally, but that’s a classic dangling-pointer/use-after-free bug. In some contexts it might make sense to guard against it for the same reasons one may validate arguments passed to a public API (and then not in the internal code)