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_ptrs 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_castseems a bit excessive for a simple derived-to-base cast. - As I understand it,
dynamic_pointer_castcreates 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_ptrby value, e.g.int foo(unique_ptr<bar> b). Callers shouldstd::movethe value into the function. -
Functions that extend the lifetime of an object should take a
shared_ptrby 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.
Although
BaseandDerivedare covariant and raw pointers to them will act accordingly,shared_ptr<Base>andshared_ptr<Derived>are not covariant. Thedynamic_pointer_castis the correct and simplest way to handle this problem.(Edit:
static_pointer_castwould 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 aconst Base&and dereference theshared_ptrwhen passing it tofoo().As an aside, because
shared_ptrtypes cannot be covariant, the rules of implicit conversions across covariant return types does not apply when returning types ofshared_ptr<T>.