Let me pose my question through an example.
#include <memory>
std::unique_ptr<int> get_it() {
auto p = new int;
return p;
}
int main() {
auto up ( get_it() );
return 0;
}
This fails to compile with the following error:
a.cpp:5:9: error: could not convert ‘p’ from ‘int*’ to ‘std::unique_ptr<int>’
return p;
^
Why isn't there an automatic conversion from a raw pointer to a unique one here? And what should I be doing instead?
Motivation: I understand it's supposed to be good practice to use smart pointers for ownership to be clear; I'm getting a pointer (which I own) from somewhere, as an int*
in this case, and I (think I) want it in a unique_ptr
.
If you're considering commenting or adding your own answer, please address Herbert Sutter's arguments for this to be possible in proposal N4029.
The answer is two-fold. All the other answers, including a OP's self-answer, addressed only one half of it.
The pointer cannot be automatically converted because:
unique_ptr
's constructor from a pointer is declared explicit
, thus considered by the compiler only in explicit contexts. This is done so to prevent accidental dangerous conversions, where a unique_ptr
can hijack a pointer and delete it without programmer's knowledge. In general, not only for unique_ptr
, it is considered a good practice to declare all single-argument constructors as explicit
to prevent accidental conversions. return
explicit by Herb Sutter (N4029, N4074), and two "responses", arguing not to do so: N4094 by Howard Hinnant and Ville Voutilainen and N4131 by Filip Roséen. After several discussions and polls the issue was closed as NAD - not a defect.Currently, there are several workarounds:
return std::unique_ptr<int>{p};
or
return std::unique_ptr<int>(p);
In c++14, you can use auto-deduction of function return type as well:
auto get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
Update: added a link to committee issue for the second point.
Because implicit construction of unique_ptr
from naked pointer would be very error-prone.
Just construct it explicitly:
std::unique_ptr<int> get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
Because std::unique_ptr
takes ownership of the pointer, and you definitely don't want to get your raw pointer delete
d accidentally.
If that would be possible, then:
void give_me_pointer(std::unique_ptr<int>) { /* whatever */ }
int main() {
int *my_int = new int;
give_me_pointer(my_int);
// my_int is dangling pointer
}
Because the conversion, or casting, requires an appropriate cast operator (on the source type) or constructor (on the target type). In this case it must be the following constructor of unique_ptr
:
explicit unique_ptr( pointer p );
Which has the explicit keyword. your get_it()
attempts implicit conversion, which explicit
prevents. Instead, you have to construct the unique_ptr
explicitly, as suggested by @Stas and @VincentSavard :
std::unique_ptr<int> get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
or even, if we want to only say unique_ptr
once...
auto get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
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