将 share_ptr < Derived > 传递为 share_ptr < Base >

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

我通常通过引用传递 shared_ptr,以避免不必要的副本:

int foo(const shared_ptr<bar>& ptr);

但是如果我试图像

int foo(const shared_ptr<Base>& ptr);


...


shared_ptr<Derived> bar = make_shared<Derived>();
foo(bar);

我可以利用

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

但这似乎并不理想,原因有二:

  • 对于简单的从派生到基本的强制转换来说,dynamic_cast似乎有点过分。
  • 据我所知,dynamic_pointer_cast创建了一个指针的副本(尽管是临时的)来传递给函数。

还有更好的解决办法吗?

为子孙后代更新:

结果是缺少头文件的问题。而且,我在这里试图做的事情被认为是一个反模式。一般来说,

  • 不影响对象生存期的函数(即对象在函数生存期内仍然有效)应该使用普通引用或指针,例如 int foo(bar& b)

  • 对象的 消耗函数(即给定对象的最终用户)应该按值取 unique_ptr,例如 int foo(unique_ptr<bar> b)。调用方应将 std::move的值放入函数中。

  • 延长对象生存期的函数应该按值取 shared_ptr,例如 int foo(shared_ptr<bar> b)。通常避免 循环参考文献的建议适用。

有关详细信息,请参阅 Herb Sutter 的 言归正传

85177 次浏览

虽然 BaseDerived是协变的,指向它们的原始指针将相应地起作用,但是 shared_ptr<Base>shared_ptr<Derived>没有协变的。dynamic_pointer_cast是处理这个问题的正确和最简单的方法。

(编辑: static_pointer_cast会更合适,因为您是从派生到基,这是安全的,不需要运行时检查。请看下面的评论。)

但是,如果您的 foo()函数不希望参与延长生存期(或者,更确切地说,参与对象的共享所有权) ,那么最好接受 const Base&并在将其传递给 foo()时取消引用 shared_ptr

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

顺便说一句,因为 shared_ptr类型不能是协变的,所以当返回 shared_ptr<T>类型时,跨协变返回类型的隐式转换规则不适用。

听起来你太努力了。shared_ptr的复制成本低廉,这是它的目标之一。通过引用传递它们实际上没有多大作用。如果不想共享,请传递原始指针。

也就是说,有两种方法可以做到这一点,我可以想到我的头顶:

foo(shared_ptr<Base>(bar));
foo(static_pointer_cast<Base>(bar));

还要检查包含派生类的完整声明的头文件的 #include是否在源文件中。

我有个问题。std::shared<derived>不会转换成 std::shared<base>。我向前声明了这两个类,这样我就可以保存指向它们的指针,但是因为我没有 #include,编译器不能看到一个类是从另一个类派生的。

如果您忘记在派生类上指定 公众人士继承,也会发生这种情况,例如,如果您像我一样写下:

class Derived : Base
{
};

而不是:

class Derived : public Base
{
};