简体   繁体   中英

Pass raw pointer to function that accepts unique_ptr as parameter

I'm trying to write a function that accepts unique_ptr to classes derived from Base as a parameters (to indicate ownership transfer). I've come up with the following code:

#include <memory>
#include <type_traits>

class Base
{
  public:
    Base() {}
};

class Derived : public Base
{
  public:
    Derived() {}
};


void foo(std::unique_ptr<Derived> _data) {}

template <class T>
void boo(std::unique_ptr<T> _data) {
    static_assert(std::is_convertible<T*, Base*>::value,
                  "Only classes derived from Base can be used as "
                  "parameter for boo");
}


int main() { foo(new Derived); }

but when I try to compile it I get and error telling me that could not convert '(operator new(1ul), (<statement>, ((Derived*)<anonymous>)))' from 'Derived*' to 'std::unique_ptr<Derived>' if I use foo and the same (plus some template details) when I use boo . If I understood everything correctly what I'm being told is that there is not constructor for std::unique_ptr<Derived> that could accept pointer for Derived . But when I looked on cppreference page for unqiue_ptr constructor I saw that there is such constructor (number 3-4).

The question is: How can I make a function that accepts unique_ptr as parameter and call it with raw pointer.

PS I'm trying to write a function that accepts unique_ptr because I want to indicate that ownership of the parameter will be transferred. If you know how to write a function with a signature that could clearly and unambiguously show that ownership is being transferred I would also accept this as a answer. This function can either template with static_assert or with Base pointer as a parameter.

PS The main problem is how to make foo(new Derived) . I know that I can use boo(std::make_unique<Derived>()) (in that case everything works) but I also really want to know why example with raw pointer does not work, because I don't know how to indicate that I'm "stealing" ownership for raw pointer.

PS Example of usage (with raw pointers) ( DOES NOT WORK )

Derived* derived_1 = new Derived;
// Do something with derived_1
boo(derived_1); // Pass to function and don't worry about `delete`
                // because you know that ownership has been
                // transferred and no longer is your concern

And with smart pointers

void foo_2(std::unique_ptr<Derived>& _data) {
     boo(std::move(_data)); 
}

std::unique_ptr<Derived> derived_2 = std::make_unique<Derived>();
// Do something with derived_2
foo(std::move(derived_2)); // Have to use `std::move`
                           // or
foo_2(derived_2);

Second one (omitting need for new function) is not as simple as first one (even though I should admit that the difference is not so big (maybe 2x typing))

Overloads 3 and 4 do not apply here. Their signature is

unique_ptr( pointer p, /* see below */ d1 ) noexcept;

unique_ptr( pointer p, /* see below */ d2 ) noexcept;

and they take a second parameter that is a custom deleter. The only overload that applies is 2 which is

explicit unique_ptr( pointer p ) noexcept;

Since it is marked as explicit it will not implicitly convert the pointer to a unique_ptr . This is a safety issues and it is correct to make it explicit. If it was not explicit then

void foo(std::unique_ptr<int> _data) {}

int main()
{
    int bar;
    foo(&bar);
}

would compile but it would be undefined behavior as _data would try to delete the pointer when it was destroyed at the end of foo .

You have to be explicit in your conversion:

int main()
{
    Derived* d = nullptr;
    BadInterface(&d); // mainly d = new Derived(..);
    foo(std::unique_ptr<Derived>(d));
}

which gives in your one liner case:

foo(std::unique_ptr<Derived>(new Derived));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM