Why is std::unique_ptr reset not the same as assignment?

Firstly, std::unique_ptr<MyClass> p = new MyClass; is not assignment, it is copy initialization. And it doesn't work because the constructor of std::unique taking a raw pointer is marked as explicit:

explicit unique_ptr( pointer p ) noexcept;

It is declared as explicit to avoid unexpected (might be dangerous) implicit conversions, eg:

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

Note that explicit constructors are not considered in copy initialization (eg std::unique_ptr<MyClass> p = new MyClass;). You can use them in direct initialization instead (eg std::unique_ptr<MyClass> p (new MyClass);). They are used to prohibit implicit conversions, but you can perform explicit conversions. Like the usage of reset, you have to do these things explicitly, to show (and make yourself) that you're pretty sure about what you're doing.

BTW: The assignment from raw pointer doesn't work either, because std::unique_ptr doesn't have an overloaded assignment operator taking a raw pointer as parameter. For the reason above, raw pointer can't be implicitly converted to std::unique_ptr, so the move assignment operator (which takes std::unique_ptr as parameter) won't be considered either.


I am trying to understand why std::unique_ptr<MyClass> p = new MyClass; does not work

The same reason as @songyuanyao mentioned, where it's declared explicit, tells that you can still initialize it in a different form of initialization that surpasses explicit:

// Valid, since now it's 'explicit'
std::unique_ptr<MyClass> p { new MyClass{} };