添加到vector的std :: shared_ptr会导致segfault

时间:2018-01-24 11:18:40

标签: c++ vector c++14 shared-ptr

我有这个示例程序。我所要做的就是在向量本身中包含的对象之间共享一个向量实例,以便它们可以从容器中操作(添加其他对象,自行删除)。

#include <iostream>
#include <memory>
#include <vector>

class SimpleClass {
private:
  std::shared_ptr<std::vector<SimpleClass>> objects;

public:
  SimpleClass (std::shared_ptr<std::vector<SimpleClass>> _objects): objects { _objects } {}

  void grow () {
    std::cout << "growing" << std::endl;
    for (int i { 0 }; i < 10; ++i) {
      std::cout << "about to add a new object" << std::endl;
      std::cout << "current simple_objects size: " << objects->size() << std::endl;
      objects->push_back(SimpleClass(objects));
      std::cout << "added a new object" << std::endl;
    }
  }
};

int main () {
  auto simple_objects = std::make_shared<std::vector<SimpleClass>>();

  for (int i { 0 }; i < 10; ++i) {
    simple_objects->push_back(SimpleClass { simple_objects });
  }

  std::cout << "simple_objects size: " << simple_objects->size() << std::endl;

  for (auto &obj: *simple_objects) {
    obj.grow();
  }

  return 0;
}

经过一些迭代后,程序存在Segmentation Fault 11

simple_objects size: 10
growing
about to add a new object
current simple_objects size: 10
added a new object
about to add a new object
current simple_objects size: 11
added a new object
about to add a new object
current simple_objects size: 12
added a new object
about to add a new object
current simple_objects size: 13
added a new object
about to add a new object
current simple_objects size: 14
added a new object
about to add a new object
current simple_objects size: 15
added a new object
about to add a new object
current simple_objects size: 16
added a new object
about to add a new object
Segmentation fault: 11

可以在此处测试该程序:https://www.onlinegdb.com/rJHSik8Hf

导致分段错误的原因以及如何防止它?

2 个答案:

答案 0 :(得分:3)

问题是您在使用课程时重新分配(复制/移动)课程。

我猜测向量分配了16个插槽。现在您要添加项目17.这意味着向量需要分配更大的数组并复制/移动现有项目。

这样可行,但请考虑当前项目(this)。它在旧阵列中。它被移动/复制,旧数组被销毁。所以这现在指向你已经解除分配的记忆,你得到了段错(幸运)。

您可能想要的是调整矢量大小并不会更改项目。您可以将项目包装在std :: unique_ptr中,它可以正常工作。

其他替代方法是修复数组的大小,以便不进行大小调整,或者不从数组中的对象修改数组。

答案 1 :(得分:1)

在堆栈上创建shared_ptr的本地副本应该可以解决问题。 (只是ptr,而不是整个矢量)

void grow () {
    auto localObjects = objects;
    std::cout << "growing" << std::endl;
    for (int i { 0 }; i < 10; ++i) {
      std::cout << "about to add a new object" << std::endl;
      std::cout << "current simple_objects size: " << localObjects->size() << std::endl;
      localObjects->push_back(SimpleClass(objects));
      std::cout << "added a new object" << std::endl;
    }
}

您还应该在迭代时创建副本,因为在迭代时修改向量。 您的代码现在正在运行而没有seg错误。 https://onlinegdb.com/H1lNlcgOSG

auto localCopy = *simple_objects;
for (auto &obj: localCopy) {
  obj.grow();
}