I am trying to understand why
std::unique_ptr<MyClass> p = new MyClass;
Does not work, but
std::unique_ptr<MyClass> p; p.reset(new MyClass);
is fine. I somewhat understand how they are different, but I would like to know why the choice was made to make them different. What is the danger in assignment not being the same as reset?
std::unique_ptr<MyClass> p = new MyClass; is not assignment, but initialization. And it doesn't work because the constructor of
std::unique taking raw pointer is marked as
explicit unique_ptr( pointer p ) noexcept;(2)
It is declared as
explicit to avoid dangerous (unexpected) implicit conversion. e.g.
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 constructor is not considered only in copy initialization (e.g.
std::unique_ptr<MyClass> p = new MyClass;). You still could use it in direct initialization (e.g.
std::unique_ptr<MyClass> p (new MyClass);). And it's used to prohibit implicit conversion, you still could perform explicit conversion. 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 overloaded assignment operator taking 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.