119

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

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

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

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

  • 对于一个简单的派生到基础的转换, Adynamic_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 的“回归基础”演讲

4

4 回答 4

60

如果您忘记在派生类上指定公共继承,也会发生这种情况,即如果您像我一样写这个:

class Derived : Base
{
};

代替:

class Derived : public Base
{
};
于 2018-07-24T14:08:17.477 回答
53

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

编辑: static_pointer_cast会更合适,因为您正在从派生转换为基础,这是安全的并且不需要运行时检查。请参阅下面的评论。)

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

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

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

于 2012-11-15T18:14:31.657 回答
16

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

我有这个问题。std::shared<derived>不会std::shared<base>投到. 我已经提前声明了这两个类,以便我可以保存指向它们的指针,但是因为我没有#include编译器,所以无法看到一个类是从另一个类派生的。

于 2017-10-19T18:25:16.633 回答
14

听起来你太努力了。shared_ptr复制成本低;这是它的目标之一。通过引用传递它们并没有真正完成太多。如果您不想共享,请传递原始指针。

也就是说,我可以想到两种方法来做到这一点:

foo(shared_ptr<Base>(bar));
foo(static_pointer_cast<Base>(bar));
于 2012-11-15T18:30:21.073 回答