将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。
答案 0 :(得分:37)
虽然Base
和Derived
是协变的,并且指向它们的原始指针会相应地起作用,但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
{
};