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:
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));
Change the signature of
f
:void f(std::unique_ptr<Derived> const &);
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>();
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
public
ly 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 topointer
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 Fruit
is 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
C++ Ifstream Error Using String as Opening File Path
Why Doesn't This Reinterpret_Cast Compile
C++ Template Typename Iterator
Sharing Precompiled Headers Between Projects in Visual Studio
How to Iterate Over a Std::Tuple in C++ 11
How to Create a C++ Boost Undirected Graph and Traverse It in Depth First Search (Dfs) Order
Do I Have to Use Atomic<Bool> for "Exit" Bool Variable
What Should a C++ Getter Return
Is There Some Ninja Trick to Make a Variable Constant After Its Declaration
Undefined Reference to Google::Protobuf::Internal::Empty_String_[Abi:Cxx11]
How to Write a Float Mat to a File in Opencv
Static Member Initialization for Specialized Template Class
What Is the Ascii Value of Eof in C