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

einpoklum picture einpoklum · Jan 19, 2016 · Viewed 12.1k times · Source

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.

Answer

Ilya Popov picture Ilya Popov · Jan 19, 2016

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.