如何正确地将shared_pointers添加到std :: vector中的派生类中?

时间:2015-05-27 09:21:16

标签: c++ vector polymorphism shared-ptr object-slicing

基本上我有这个设置:

class B { /* ... */};
class C1 : public B { /* ... */};
class C2 : public B { /* ... */};

class X
{
  std::vector<shared_ptr<B>> m_vec;
  void addToVector(B* b);
}

addToVector无法知道有多少班级来自B而且不应该关心。它会像这样调用:

someFunction() {
  C1 tmp;
  /* do something with tmp */
  m_myX.addToVector(&tmp);
}

所以在someFunction结束时,tmp超出范围并将被删除。 addToVector必须将一个shared_ptr推送到向量中的tmp副本,但它怎么能这样做呢?

void X::addToVector(B* b)
{
  int i = sizeof(b); // allways sizeof(B) :(
  shared_ptr<B> np(b);
  m_vec.push_back(np); // garbage collected after calling fn returns :(
}

它应该做的是:

  • 通过调用正确的
  • 类的复制构造函数/运算符来复制对象b指向的对象
  • 将该副本的shared_ptr推送回向量。

我该怎么做?

2 个答案:

答案 0 :(得分:4)

您正在堆栈上创建一个对象,然后将其地址提供给shared_ptr,它将尝试delete堆栈中的对象,这是未定义的行为。

解决方案是停止这样做:

void someFunction() {
  C1* c = new C1;
  /* do something with *c */
  m_myX.addToVector(c);
}

现在堆上有一个对象,可以由shared_ptr拥有。没有必要复制它。

只有当B具有虚拟析构函数时,这才能正常工作,但可以通过首先创建shared_ptr来避免(并且可以使代码更安全,更清晰):

void someFunction() {
  auto c = std::make_shared<C1>();
  /* do something with *c */
  m_myX.addToVector(c);
}

void X::addToVector(std::shared_ptr<B> b)
{
  m_vec.push_back(np);
}

现在堆对象在创建后由shared_ptr管理,然后安全地存储在向量中。

答案 1 :(得分:2)

你的'someFunction'看起来很奇怪......(为什么不首先将tmp创建为shared_ptr?)

要使它工作,你必须创建'虚拟构造函数' - 在B中添加虚拟方法B* deepCopy() const,并在所有子类中实现它,它的主体应该基于模式:{ return new DerivedType(*this); }

如果您想要干净 - 请deepCopy返回shared_ptr并使用make_shared