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.