Во-первых, 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
, вы должны делать эти вещи явно , чтобы показать (и сделать себя), что вы почти уверены в том, что делаете.
Кстати: назначение из необработанного указателя также не работает, потому что std::unique_ptr
не имеет перегруженного оператора присваивания, принимающего необработанный указатель в качестве параметра. По вышеуказанной причине необработанный указатель не может быть неявно преобразован в std::unique_ptr
, поэтому оператор присваивания перемещения (который принимает std::unique_ptr
в качестве параметра) также не будет рассматриваться.