What are the differences between std :: move and unique_ptr :: reset?

For std::unique_ptr p1 and p2 , what are the differences between std::move() and std::unique_ptr::reset() ?

 p1 = std::move(p2); p1.reset(p2.release()); 
+8
c ++ c ++ 11 unique-ptr
source share
3 answers

The answer should be obvious from the standard specification of the destination of the move in [unique.ptr.single.assign] / 2:

Effects: transfers ownership from u to *this , as if it were calling reset(u.release()) , and then assigning from std::forward<D>(u.get_deleter()) .

Clearly moving the destination does not match reset(u.release()) because it does something extra.

An additional effect is important, without it you can get undefined behavior with user deletions:

 #include <cstdlib> #include <memory> struct deleter { bool use_free; template<typename T> void operator()(T* p) const { if (use_free) { p->~T(); std::free(p); } else delete p; } }; int main() { std::unique_ptr<int, deleter> p1((int*)std::malloc(sizeof(int)), deleter{true}); std::unique_ptr<int, deleter> p2; std::unique_ptr<int, deleter> p3; p2 = std::move(p1); // OK p3.reset(p2.release()); // UNDEFINED BEHAVIOUR! } 
+15
source share

The first method may warn you, for example, about a destructor mismatch. In addition, release() is a very dangerous function, and your trivial example is correct, but many other uses are not. It’s better to just never, never use this feature.

+5
source share

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.

-2
source share

All Articles