Std::Unique_Ptr with Derived Class

unique_ptr to a derived class as an argument to a function that takes a unique_ptr to a base class

You have three options:

  1. Give up ownership. This will leave your local variable without access to the dynamic object after the function call; the object has been transferred to the callee:

    f(std::move(derived));
  2. Change the signature of f:

    void f(std::unique_ptr<Derived> const &);
  3. Change the type of your variable:

    std::unique_ptr<base> derived = std::unique_ptr<Derived>(new Derived);

    Or of course just:

    std::unique_ptr<base> derived(new Derived);

    Or even:

    std::unique_ptr<base> derived = std::make_unique<Derived>();
  4. Update: Or, as recommended in the comments, don't transfer ownership at all:

    void f(Base & b);

    f(*derived);

unique_ptr to a derived class as an argument to a function that takes a unique_ptr to a base class and take owenership

The function must accept the unique_ptr by value:

  void addElement (std::unique_ptr<Base> base)
{
myVector.push_back(std::move(base));
}

and then call the member function like this:

MyClass myClass;

auto b = std::make_unique<Base>();
myClass.addElement(std::move(b));

auto d = std::make_unique<Derived>();
myClass.addElement(std::move(d));

or even better avoid the variables because you cannot use them anyway after the function call:

MyClass myClass;

myClass.addElement(std::make_unique<Base>());

myClass.addElement(std::make_unique<Derived>());

Transfer ownership of a derived class unique_ptr to its abstract base class unique_ptr

To transfer ownership of a derived class managed by a derived class unique_ptr to a base class unique_ptr, you can (and should) use move semantics.

    std::unique_ptr<Derived> foo = std::make_unique<Derived>();
std::unique_ptr<Base> bar = std::move(foo);

To return ownership to a derived unique_ptr, you need to get a little messier:

    std::unique_ptr<Derived> foo = std::make_unique<Derived>();
std::unique_ptr<Base> bar = std::move(foo);

std::unique_ptr<Derived> biz(static_cast<Derived*>(bar.release()));

If you're unsure of the actual type of the pointer, then a dynamic cast can be used to check that it's correct. Note that we use std::unique_ptr<Base>::get() in the conditional, since we're not sure we want to release ownership yet. If this passes, then we can call std::unique_ptr<Base>::release().

    std::unique_ptr<Derived> foo = std::make_unique<Derived>();
std::unique_ptr<Base> bar = std::move(foo);

// dynamic cast if we're unsure that it is castable
if (dynamic_cast<Derived*>(bar.get())) {
foo.reset(static_cast<Derived*>(bar.release()));
}

see it in action

std::unique_ptr with derived class

If they are polymorphic types and you only need a pointer to the derived type use dynamic_cast:

Derived *derivedPointer = dynamic_cast<Derived*>(basePointer.get());

If they are not polymorphic types only need a pointer to the derived type use static_cast and hope for the best:

Derived *derivedPointer = static_cast<Derived*>(basePointer.get());

If you need to convert a unique_ptr containing a polymorphic type:

Derived *tmp = dynamic_cast<Derived*>(basePointer.get());
std::unique_ptr<Derived> derivedPointer;
if(tmp != nullptr)
{
basePointer.release();
derivedPointer.reset(tmp);
}

If you need to convert unique_ptr containing a non-polymorphic type:

std::unique_ptr<Derived>
derivedPointer(static_cast<Derived*>(basePointer.release()));

Pointer to a std::unique_ptr of derived class from base class

If you want to reference an object which is owned elsewhere in your code, std::shared_ptr is your way to go (at least if you want to achieve what you are showing in the example which is part of your question). Then, if you want to downcast base class std::shared_ptr to a derived class std::shared_ptr you can do the following:

#include <iostream>
#include <memory>

struct Base {};

struct Derived : Base {};

int main() {
std::shared_ptr<Base> base = std::make_shared<Base>();
std::shared_ptr<Derived> derived = std::static_pointer_cast<Derived>(base);

return 0;
}

Furthermore, following code may mimic your situation and what you want to achieve a bit better:

#include <iostream>
#include <memory>

struct Base {};

struct Derived : Base {};

std::unique_ptr<Base> const& get_unique_ptr() {
static std::unique_ptr<Base> base = std::make_unique<Base>();
return base;
}

int main() {
std::unique_ptr<Base> const& base = get_unique_ptr();
std::unique_ptr<Derived> derived(static_cast<Derived*>(base.get()));

return 0;
}

Note that above solution may lead to unwanted behavior of releasing the same pointer twice.

Adding derived class object to vectorunique_ptr of base class

Similar to how the default member visibility of class is private, inheritance is also private unless otherwise specified. You need to inherit from Organism publicly so that std::unique_ptr is able to see and perform the conversions you expect.

class Sheep : public Organism {
public:
Sheep( coordinates organism_pos, World* world);
}

Your constructor also needs to be public so that std::make_unique can see and use it.

Why does unique_ptrDerived implicitly cast to unique_ptrBase?

The bit of magic you're looking for is the converting constructor #6 here:

template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;

It enables constructing a std::unique_ptr<T> implicitly from an expiring std::unique_ptr<U> if (glossing over deleters for clarity):

unique_ptr<U, E>::pointer is implicitly convertible to pointer

Which is to say, it mimicks implicit raw pointer conversions, including derived-to-base conversions, and does what you expect™ safely (in terms of lifetime – you still need to ensure that the base type can be deleted polymorphically).

Passing unique_ptrDerived& to a function accepting unique_ptrBase&

What dangerous situation am I potentially creating?

Imagine the following implementation for foo:

void foo(std::unique_ptr<Base>& d){
d.reset(new Base);
}

You now have a std::unique_ptr<Derived> pointing to an object which is not of type Derived, and the compiler couldn't give you any kind of warning about it.

The correct solution to your problem, as explained in the comments, is to take a std::unique_ptr<Base> by value, and move it at the call site.

void foo(std::unique_ptr<Base> d) {
// move d to your list
}

int main() {
unique_ptr<Derived> b = make_unique<Derived>();
foo(std::move(b));
}

Instantiate unique_ptr to derived class from vector of base class where derived class has been stored

You don't want ownership transfer, so cast only the pointer:

auto& banana = dynamic_cast<Banana&>(*product[0]);
auto c = banana.color;

dynamic_cast might be replaced by static_cast if you are really sure that Fruitis really a Banana.
In case your are wrong, static_cast would lead to UB whereas you can check validity with dynamic_cast (exception with cast to reference or null pointer with cast to pointer).



Related Topics



Leave a reply



Submit