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

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-06 17:26:23

问题


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.


回答1:


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.




回答2:


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



回答3:


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
}



回答4:


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



回答5:


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


来源:https://stackoverflow.com/questions/34882140/why-cant-a-pointer-be-automatically-converted-into-a-unique-ptr-when-returning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!