2

我基本上有这个设置:

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必须 push_back 一个 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 指向的对象
  • push_back 将 shared_ptr 复制到向量中。

我怎样才能做到这一点?

4

2 回答 2

4

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

解决方案是停止这样做:

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

现在你在堆上有一个对象,它可以由 a 拥有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创建就被管理,然后安全地存储在向量中。

于 2015-05-27T09:32:34.293 回答
2

你的'someFunction'看起来很奇怪......(为什么不首先创建tmpshared_ptr

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

如果你想干净 - 让deepCopy返回shared_ptr和使用make_shared

于 2015-05-27T09:27:37.110 回答