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{} };