将shared_ptr <derived>作为shared_ptr <base /> </derived>传递

时间:2012-11-15 18:04:46

标签: c++ casting c++11 shared-ptr smart-pointers

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)。通常建议避免使用circular references

有关详细信息,请参阅Herb Sutter的Back to Basics talk

4 个答案:

答案 0 :(得分:37)

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

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

但是,如果您的foo()函数不希望参与延长生命周期(或者更确切地说,参与对象的共享所有权),那么最好接受const Base&在将shared_ptr传递给foo()时将void foo(const Base& base); [...] shared_ptr<Derived> spDerived = getDerived(); foo(*spDerived); 取消引用。

shared_ptr

另外,由于shared_ptr<T>类型不能协变,因此返回协变返回类型的隐式转换规则在返回{{1}}类型时不适用。

答案 1 :(得分:11)

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

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

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

答案 2 :(得分:5)

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

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

答案 3 :(得分:2)

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

class Derived : Base
{
};