Why can't a pointer be automatically converted into a unique_ptr when returning it?

◇◆丶佛笑我妖孽 提交于 2019-12-04 23:13:52

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 statement is considered by the standard an implicit context, and thus the explicit constructor is not applicable. There was an ongoing discussion if this decision is right, reflected in EWG issue 114, including links to several proposals: two versions of proposals to make 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.

Stas

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 deleted 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);
}

Because it is dangerous.

Use std::make_unique() from C++14:

std::unique_ptr<int> get_it()
{
    auto p = std::make_unique<int>();
    return p;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!