The second version may not be an exception. This is equivalent to:
auto __tmp = p2.release(); p1.reset(__tmp);
Thus, if the call to std::unique_ptr::reset throws (which could be if the throw of the managed object is deleted), then you have an unreferred object that will never be destroyed. In the case of a move assignment, std::unique_ptr can (and should) wait with the actual move until the original p1 object is destroyed correctly.
But note that this is only a problem if the managed objectβs destructor could throw away, which in almost all cases is wrong in itself, or if you are using a custom delete item that can be thrown. Thus, in practice, there is usually no behavioral difference between two pieces of code.
EDIT: In the end, Jonathan points out in his comment that the standard deviation is required by the standard not to be thrown, which really makes the std::unique_ptr::reset throw pretty unlikely / inappropriate, but it also indicates that there is another difference as only the move destination also moves any user deletors to which he also wrote a response.
But, despite the actual behavior that has arisen, there is a big conceptual difference between them. If the transition assignment is appropriate, then complete the redirection assignment and try not to emulate it with any other code. In fact, I can not imagine any reason to replace the first piece of code one by one with the second. DeadMG is right that std::unique_ptr::release should only be used if you really know what you are doing and in what context you are messing with unmanaged dynamic objects.
Christian rau
source share