传递 shared_ptr<Derived>作为 shared_ptr<Base>

2021-12-31 00:00:00 casting c++ c++11 shared-ptr smart-pointers

将派生类型的 shared_ptr 传递给采用基类型 shared_ptr 的函数的最佳方法是什么?

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?

我通常通过引用传递 shared_ptr 以避免不必要的复制:

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);

我可以使用

foo(dynamic_pointer_cast<Base, Derived>(bar));

但这似乎不是最理想的,原因有两个:

but this seems sub-optimal for two reasons:

  • 一个 dynamic_cast 对于一个简单的派生到基础的转换来说似乎有点过分.
  • 据我所知,dynamic_pointer_cast 创建要传递给函数的指针的副本(尽管是临时副本).
  • 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.

有更好的解决方案吗?

原来是缺少头文件的问题.此外,我在这里尝试做的事情被认为是一种反模式.一般来说,

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,

  • 不影响对象生命周期的函数(即对象在函数的持续时间内保持有效)应该采用普通引用或指针,例如int foo(bar& b).

消费一个对象(即给定对象的最终用户)的函数应该采用一个 unique_ptr 按值,例如int foo(unique_ptr b).调用者应该将值std::move 放入函数中.

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.

延长对象生命周期的函数应该采用 shared_ptr 值,例如int foo(shared_ptr b).避免循环引用的通常建议适用.

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.

有关详细信息,请参阅 Herb Sutter 的回归基础讲座.

See Herb Sutter's Back to Basics talk for details.

推荐答案

虽然 BaseDerived 是协变的并且指向它们的原始指针会相应地起作用,shared_ptr<Base>shared_ptr 是非协变的.dynamic_pointer_cast 是处理此问题的正确且最简单的方法.

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.

( static_pointer_cast 会更合适,因为您是从派生转换到基类,这是安全的,不需要运行时检查.请参阅下面的评论.)

( 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.)

然而,如果你的 foo() 函数不想参与延长生命周期(或者,更确切地说,参与对象的共享所有权),那么最好接受一个 const Base& 并在将 shared_ptr 传递给 foo() 时取消引用它.

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);

顺便说一句,因为 shared_ptr 类型不能协变,当返回 shared_ptr 类型时,跨协变返回类型的隐式转换规则不适用.

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>.

相关文章