Passing shared_ptr<Derived> as shared_ptr<Base>

c++, c++11, casting, shared-ptr, smart-pointers

Solution

Although `Base` and `Derived` are covariant and raw pointers to them will act accordingly, `shared_ptr<Base>` and `shared_ptr<Derived>` are not covariant. The `dynamic_pointer_cast` is the correct and simplest way to handle this problem.

(Edit: `static_pointer_cast` would be more appropriate because you're casting from derived to base, which is safe and doesn't require runtime checks. See comments below.)

However, if your `foo()` function doesn't wish to take part in extending the lifetime (or, rather, take part in the shared ownership of the object), then its best to accept a `const Base&` and dereference the `shared_ptr` when passing it to `foo()`.

void foo(const Base& base);
[...]
shared_ptr<Derived> spDerived = getDerived();
foo(*spDerived);

As an aside, because `shared_ptr` types cannot be covariant, the rules of implicit conversions across covariant return types does not apply when returning types of `shared_ptr<T>`.

Problem

What is the best method to go about passing a `shared_ptr` of a derived type to a function that takes a `shared_ptr` of a base type? I generally pass `shared_ptr`s by reference to avoid a needless copy: ``` int foo(const shared_ptr<bar>& ptr); ``` but this doesn't work if I try to do something like ``` int foo(const shared_ptr<Base>& ptr); ... shared_ptr<Derived> bar = make_shared<Derived>(); foo(bar); ``` I could use ``` foo(dynamic_pointer_cast<Base, Derived>(bar)); ``` but this seems sub-optimal for two reasons: - A `dynamic_cast` seems a bit excessive for a simple derived-to-base cast. - As I understand it, `dynamic_pointer_cast` creates a copy (albeit a temporary one) of the pointer to pass to the function. Is there a better solution? Update for posterity: It turned out to be an issue of a missing header file. Also, what I was trying to do here is considered an antipattern. Generally, Functions that don't impact an object's lifetime (i.e. the object remains valid for the duration of the function) should take a plain reference or pointer, e.g. `int foo(bar& b)`. Functions that consume an object (i.e. are the final users of a given object) should take a `unique_ptr` by value, e.g. `int foo(unique_ptr<bar> b)`. Callers should `std::move` the value into the function. Functions that extend the lifetime of an object should take a `shared_ptr` by value, e.g. `int foo(shared_ptr<bar> b)`. The usual advice to avoid circular references applies. See Herb Sutter's Back to Basics talk for details.

Original source

Related problems