For many use cases you do not need all that knowledge. C++ is fast enough to not have to care. It's when you hit a wall that you need to get the extra tools to make things work.
I have seen developers discussing obscure optimizations for a piece of code that will only be called once several minutes, and only after unparsing a JSON String. That one less instruction call by the CPU makes no difference whatsoever.
In C++, a move is an awkward kind of mutable copy operation with a special overloading rule that allows binding to rvalue references. There is nothing obvious about how it works, people get tripped up by it all the time along with all the additional complexity about when moves happen vs. when an elision happens vs. when a copy happens, the fact that T&& means wildly different things depending on whether T is a template parameter, and the bloated set of value categories introduced by it: glvalues, xvalues, rvalues, prvalues.
I absolutely sympathize with anyone who doesn't feel like knowing all these C++isms.
>C++ had to be backward compatible with pre C++11 and couldn't make destructive moves work.
This is simply untrue as per the original proposal which left the door open to destructive moves (that door is now closed). There is nothing about destructive moves that make it incompatible with C++98/03. The main concern for destructive moves was how to deal with moves across an inheritance hierarchy, certainly a reasonable concern to have but nothing insurmountable by any means.
The issue is that, as most things involving C++, decisions are pondered upon endlessly by a very small group of people not on the basis of their technical qualifications but on the basis of being able to to participate in the C++ standardization process, which requires physically travelling to numerous locations around the world at ones own expense. If C++ had a more open standardization process that embraced research from other languages and communities, this issue would have been solved.
You can read the original proposal here:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n137...
Note the section on destructive moves which doesn't mention anything to do with compatibility, and finally note why it wasn't adopted:
"In the end, we simply gave up on this as too much pain for not enough gain."
By "we" the author means three people gave up on it. Three people who couldn't find a solution to a problem (which has a solution) is why C++ is forever stuck without destructive move semantics.
In Rust, your code won't even compile if you try to use a moved-from value. In C++ what happens depends on what the moved-from state looks like.
In C++, if you do something like use a moved-from value, it's really not obvious what "should" happen at all. It's not even obvious whether that should compile or be undefined behaviour.
> I absolutely sympathize with anyone who doesn't feel like knowing all these C++isms.
Any C++ programmer should agree with this. We don't want to know all of this bullshit and in fact would largely prefer if the compiler would know it for us...
C++ gives a good abstraction for very low level operations, and has a great long term backward compatibility story. As such learning the details can be useful for anyone doing low level work over the long term. Rust is aiming at this space but doesn't have the long term track record (yet?). There are hundreds of other languages that you can also choose from with pros and cons. No matter what language you choose though, because low level details are important to you, you must learn fiddly low level bits to some extent as when move vs copy is used is by nature important.
Of course part of this is about age. C++ goes back to the early 1970s (the C roots). In that time a lot of things have change. We have learned not to do things that seemed good. We have found better ways. The way hardware works has changed. What is important to speed has changed. Compilers now do optimizations. Whatever language you choose today will look dated in 50 years.