Ответ 1
Во-первых, std::unique_ptr<MyClass> p = new MyClass;
не является присвоением, это инициализация копирования. И это не работает, потому что конструктор std::unique
с необработанным указателем помечен как explicit
:
explicit unique_ptr( pointer p ) noexcept;
Он объявлен как explicit
чтобы избежать опасных (неожиданных) неявных преобразований, например:
void foo(std::unique_ptr<int> uptr);
int *rptr = new int;
foo(rptr); // suppose rptr is implicitly converted to std::unique_ptr<int>
// then the ownership is passed to the parameter uptr
// when foo() returns uptr is destroyed; the pointer managed by it is deleted too
// since rptr has been deleted continue to deference on it leads to UB
*rptr = 42; // UB
Обратите внимание, что explicit
конструкторы не рассматриваются при инициализации копии (например, std::unique_ptr<MyClass> p = new MyClass;
). Вы можете использовать их при прямой инициализации (например, std::unique_ptr<MyClass> p (new MyClass);
). Они используются для запрета неявных преобразований, но вы можете выполнять явные преобразования. Подобно использованию reset
, вы должны делать это явно, чтобы показать (и заставить себя), что вы полностью уверены в том, что вы делаете.
BTW: назначение из raw-указателя тоже не работает, потому что std::unique_ptr
не имеет перегруженного оператора присваивания, беря в качестве параметра необработанный указатель. По вышеуказанной причине необработанный указатель не может быть неявно преобразован в std::unique_ptr
, поэтому оператор присваивания перемещения (который принимает параметр std::unique_ptr
как параметр) также не рассматривается.