I'm not sure the "afraid to commit to" is a valid interpretation. The requirements that the C++ standard specifies for moved-from objects turns that hypothetical issue into a non-problem. In C++, if you move an object then after the move the object must be left in a valid state. That's it. This means the object can be safely destroyed.
You are also free to implement whatever semantics your moved-from object has. If you want your moved-from object to throw an exception, you are free to implement that. If instead you want to ensure your moved-from can be reused you are also free to do so. If you want to support zombie objects then nothing prevents you from going that path. It's up to you. The only thing the standard specifies is that once the lifetime of that object ends, it can be safely destroyed. That sounds both obvious and elegant, don't you agree?
I don't know what nightmares you have. The only requirement that C++ specifies for moved-from objects is that they remain valid. Meaning, they can be safely destroyed.
You can go way out of your way and reuse an object that was just moved, but that's a decision you somehow made, and you have the responsibility of adding your reinitialization or even move logic to get that object back in shape. That is hardly something that sneaks up on you.
The problem with the current move semantics is that, compared to e.g. Rust: 1) the compiler generates unnecessary code and 2) instead of just implementing class T you must implement a kind of optional<T>.
Which means, that after all those years of using smart pointers I find myself ditching them in favor of plain pointers like we did in the 90's.
I'm not OP, but the only requirements that C++ imposed on moved-from objects is that they remain valid objects. Meaning, they can be safely destroyed or reused by reassigning or even moving other objects into them. I have no idea what OP could be possibly referring to.
I don't know what you mean by "compiler generates unnecessary code" or why you see that as a problem. I also have no idea what you mean by "a kind of optional". The only requirement on moved-from objects is that they must be left in a valid state. Why do you see that as a problem?
Regarding #2, take Resource Acquisition Is Initialization (RAII) as an example - in RAII, the existence of an object implies the existence of a resource. Now, if you want to be able to move, the object becomes "either the resource exists or it was moved out". As someone else noted in the comments, this affects not only the destructor. Methods cannot assume the existence of the resource, they have to check it first. Kind of like optional<MyResource>.
Everyone who ever uses C++ uses move semantics all the time,including move elision. It's not an obscure feature.
> (...) this is for me the most frustrating thing about C++ full stop.
I've been using C++ for years and I have no idea what you could be possibly referring to. The hardest aspect of move semantics is basically the rule of 5. From that point, when you write a class you have the responsibility to specify how you want your class to be moved and how you want your moved-from class to look like, provided that you ensure you leave it in a valid state.
That's it.
What exactly do you believe needs fixing?
The more unfortunate, perhaps disingenuous part is that the proposal paper tries to pretend you can make the destructive move later if you need it once you've got their C++ move.
But actually what they're proposing is that "move + create" + "destroy" = "move". So, that's extra work it's not the same thing at all and sure enough in the real world this means extra work, from compilers, from programmers and sometimes (if it isn't removed by the optimiser) from the runtime program.
> The more unfortunate, perhaps disingenuous part is that the proposal paper tries to pretend you can make the destructive move later if you need it once you've got their C++ move.
For reference, I think N1377 is the original move proposal [0]. Quoting from that:
> Alternative move designs
> Destructive move semantics
> There is significant desire among C++ programmers for what we call destructive move semantics. This is similar to that outlined above, but the source object is left destructed instead of in a valid constructed state. The biggest advantage of a destructive move constructor is that one can program such an operation for a class that does not have a valid resourceless state. For example, the simple string class that always holds at least a one character buffer could have a destructive move constructor. One simply transfers the pointer to the data buffer to the new object and declares the source destructed. This has an initial appeal both in simplicity and efficiency. The simplicity appeal is short lived however.
> When dealing with class hierarchies, destructive move semantics becomes problematic. If you move the base first, then the source has a constructed derived part and a destructed base part. If you move the derived part first then the target has a constructed derived part and a not-yet-constructed base part. Neither option seems viable. Several solutions to this dilemma have been explored.
<snip>
> In the end, we simply gave up on this as too much pain for not enough gain. However the current proposal does not prohibit destructive move semantics in the future. It could be done in addition to the non-destructive move semantics outlined in this proposal should someone wish to carry that torch.
[0]: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n13...