# V825. Expression is equivalent to moving one unique pointer to another. Consider using 'std::move' instead.

Анализатор обнаружил фрагмент кода, в котором совместно используются функции 'std::unique_ptr::reset' и 'std::unique_ptr::release'.

Рассмотрим простой пример кода:

    void foo()
    {
      auto p = std::make_unique<int>(10);
      ....
      std::unique_ptr<int> q;
      q.reset(p.release());
      ....
    }

Формально, такой вызов эквивалентен перемещению умного указателя:

    void foo()
    {
      auto p = std::make_unique<int>(10);
      ....
      auto q = std::move(p);
      ....
    }

В данном случае, предложение анализатора заменить цепочку вызовов 'q.reset(p.release())' на 'q = std::move(p) ' улучшит прозрачность кода. Однако, может возникнуть ситуация, когда перемещение умного указателя будет являться обязательным. Например, при использовании пользовательского функционального объекта для освобождения ресурса:

    class Foo { .... };

    struct deleter
    {
      bool use_free;

      template<typename T>
      void operator()(T *p) const noexcept
      {
        if (use_free)
        {
          p->~T();
          std::free(p);
        }
        else
        {
          delete p;
        }
      }
    };

Рассмотрим два небольших примера, первый с перемещением умного указателя с пользовательским функциональным объектом для освобождения ресурса, при помощи паттерна 'reset' - 'release':

    void bar1()
    {
      std::unique_ptr<Foo, deleter> p { (int*) malloc(sizeof(Foo)),
                                         deleter { true } };
      new (p.get()) Foo { .... };

      std::unique_ptr<Foo, deleter> q;

      q.reset(p.release()); // 1
    }

и второй пример, с помощью функции 'std::move':

    void bar2()
    {
      std::unique_ptr<Foo, deleter> p { (int*) malloc(sizeof(Foo)),
                                        deleter { true } };
      new (p.get()) Foo { .... };

      std::unique_ptr<Foo, deleter> q;

      q = std::move(p);     // 2
    }

В втором примере при перемещении указателя 'p' в 'q' функция 'std::move' позволит переместить также и функциональный объект типа 'deleter' для освобождения ресурса. В первом примере цепочка вызовов 'q.reset(p.release())' этого не сделает. Это приведет к тому, что исходный объект типа 'Foo', аллоцированный на куче через вызов 'malloc' и сконструированный оператором 'placement new', будет неверно освобожден путем вызова оператора 'delete'. Такой код неминуемо приведёт к неопределённому поведению программы.