4 ms·
> No different than when they added move the first time in C++11 and everybody had to learn the difference between copy and move. Yes, it's not the first time
by roca 7y ago
> No different than when they added move the first time in C++11 and everybody had to learn the difference between copy and move.
Yes, it's not the first time the cognitive load of C++ has increased.
> No different than Rust programmers learning the difference between Rust's move and C++'s move.
Learning concepts in a new language doesn't increase cognitive load in the same way. In C++ you will have to decide which kind of move to use in any given situation, and deal with code using multiple kinds of moves. Learning Rust doesn't create such issues.
> Adding that little bit of extra state for the compiler to track might be helpful.
It'll be interesting to see how that goes. In Rust the compiler ensures safe code can't access a moved-out-of object, but that depends on Rust's strong aliasing guarantees. In C++ I guess accessing a moved-out-of object will have to be a new kind of undefined behavior, creating new classes of bugs and requiring new sanitizers and approximate static checkers to be implemented.
- olliej 7y agoHappily the undefined behavior plan for C++ seems to be, in addition to putting all the UB definitions in one place, requiring all new proposals justify why something should be UB or UD. E.g. no more "it requires work to say what happens" UB cop outs - if something can be defined it should be. In this case I'd say that a value cannot be used after it is destructively moved. There is no reason for that to be UB, when the language can just refuse to compile it.
- roca 7y agoIn general the compiler will not be able to prove that the value is not used again, because of possible aliasing. E.g. if you called a method on the object, then the compiler would need to be able to prove that 'this' hasn't been stashed away somewhere so it can be used again (without otherwise triggering undefined behavior) after the object has been moved out of. I.e. to have the compiler prove absence of use-after-move requires the same sort of lifetime analysis it would need to prove absence of use-after-free, and that is simply not realistic for C++.
- olliej 7y agoUse after free (through references) is a standard problem in C++ through anything. But you can say post-move a value is dead, and use of existing references would be UB (sigh, but that isn't new). But to address your point: I'm a muppet and didn't think about conditional move in a loop. I had been thinking that you require that any conditional block has to end with a moved value int he same state - e.g. if (a) {move(x)} else {} The compiler would say both blocks must end with x being dead, so the else block would be required to call x.~X(); But yeah, that fails completely if you have for (...i...) { if (i) move(x) } because my clever rule means that x would have to die at the end of the first loop. But the general problem I have with std::move currently is that there's no guaranteed death - the fact that post std::move a destructor will still run, or the object can just continue to be used in general means that your code has to be made defensive against already being logically dead - even if just the destructor.
- roca 7y agoRust takes a conservative approach here --- you can't use x if it might have been moved along some control-flow path leading up to the current point. C++ could do that too. > Use after free (through references) is a standard problem in C++ through anything. But you can say post-move a value is dead, and use of existing references would be UB (sigh, but that isn't new). OK, arguably aliased-use-after-move could be treated as an existing form of UB. Sanitizers and static checkers would still need to be updated, however.