
I disagree. Suppose we have a function foo(shared_ptr<int> &&p) that might or might not move from p. For instance, foo might be one of several potential consumers of the shared_ptr. In this case, having the move constructor automatically zero out p would be a nice way to let the client know that p was actually moved from. It would enable code like the following:
shared_ptr<int> p(new int(1)); foo(move(p)); if (p) { // foo didn't want it, try the next potential consumer bar(move(p)); } else { return; // foo consumed our shared_ptr, so we are done. }
Of course you can always write: shared_ptr<int> p(new int(1)); if( !foo(move(p)) ) // foo didn't want it, try the next potential consumer bar(move(p)); } else { return; // foo consumed our shared_ptr, so we are done. }
Also, leaving the shared_ptr in an inconsistent state can cause intermittent crashes far away from where the move occurred. This is unfair to the person who will be debugging the crash, who may well be someone different from the person who wrote the code with the move statement.
Saying that something is undefined behavior doesn't mean that we shouldn't provide debugging features to help detect ill-formed code. Emil Dotchevski