简体   繁体   English

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

[英]How do i correctly add shared_pointers to probably derived classes into a std::vector?

I have basically this setup: 我基本上有这个设置:

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

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

addToVector cant know how many classes derive from B and should not care. addToVector无法知道从B派生出多少个类,因此不必在意。 It will be called like this: 它将被这样称呼:

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

so at the end of someFunction , tmp is getting out of scope and will be deleted. 因此,在someFunction的末尾,tmp超出范围,将被删除。 addToVector has to push_back a shared_ptr to a copy of tmp into the vector, but how can it do that? addToVector必须将一个shared_ptr addToVector回一个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 :(
}

What it should do is: 它应该做的是:

  • make a copy of the object b is pointing to by calling the copy constructor/operator of the correct class 通过调用正确类的副本构造函数/运算符来复制b指向的对象
  • push_back a shared_ptr to that copy into the vector. push_back一个shared_ptr将该副本复制到向量中。

How can i do this? 我怎样才能做到这一点?

You are creating an object on the stack and then giving its address to a shared_ptr which will try to delete an object on the stack, which is undefined behaviour. 您正在堆栈上创建一个对象,然后将其地址提供给shared_ptr ,它将尝试delete堆栈上的对象,这是未定义的行为。

The solution is to stop doing that: 解决方案是停止这样做:

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

Now you have an object on the heap, which can be owned by a shared_ptr . 现在,您在堆上有了一个对象,该对象可以由shared_ptr拥有。 There's no need to make a copy of it. 无需复制它。

This will only work correctly if B has a virtual destructor, but that can be avoided (and the code can be made safer and cleaner) by creating a shared_ptr in the first place: 这只有在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);
}

Now the heap object is managed by shared_ptr as soon as it's created, and then safely stored in the vector. 现在,堆对象一创建就由shared_ptr管理,然后安全地存储在向量中。

your 'someFunction' looks strange... (why not create tmp as shared_ptr in the first place?) 您的“ someFunction”看起来很奇怪...(为什么不首先将tmp创建为shared_ptr ?)

to make it work you will have to create 'virtual constructor' - add virtual method B* deepCopy() const in B, and implement it in all subclasses, it's body should be based on pattern: { return new DerivedType(*this); } 要使其工作,您将必须创建“虚拟构造函数”-在B* deepCopy() const添加虚拟方法B* deepCopy() const ,并在所有子类中实现它,它的主体应基于以下模式: { return new DerivedType(*this); } { return new DerivedType(*this); }

If you want to be clean - make deepCopy returning shared_ptr and using make_shared . 如果您想保持干净,请使deepCopy返回shared_ptr并使用make_shared

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM