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

c++, c++11, unique-ptr

Solution

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

Effects: Transfers ownership from `u` to `*this` as if by calling `reset(u.release())` followed by an assignment from `std::forward<D>(u.get_deleter())`.

Clearly move assignment is not the same as `reset(u.release())` because it does something additional.

The additional effect is important, without it you can get undefined behaviour with custom deleters:

#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!
}

Problem

For `std::unique_ptr`s `p1` and `p2`, what are differences between `std::move()` and `std::unique_ptr::reset()`? ``` p1 = std::move(p2); p1.reset(p2.release()); ```

Original source