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::reset Destroys the object currently managed by the unique_ptr (if any) and takes ownership of p. If p is a null pointer (such as a default-initialized pointer), the unique_ptr becomes empty, managing no object after the call.
An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.
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{} };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With