【问题标题】:c++ garbage values in vector of pointer指针向量中的c ++垃圾值
【发布时间】:2016-01-26 19:11:21
【问题描述】:

当我这样做时:

for(i=0; i<size; i++){
    //create objectA here
    vectorA.push_back(objectA);
    pvectorA.push_back(&vectorA[i]);
}

pvectorA 的某些元素是垃圾。但是,当我这样做时:

for(i=0; i<size; i++){
    //create objectA here
    vectorA.push_back(objectA);

}
for(i=0; i<size; i++){
    pvectorA.push_back(&vectorA[i]);
}

一切正常。为什么会这样?

【问题讨论】:

  • 你是如何创建objectA的?主要区别在于,在第一个版本中,您每次添加一个不同的指针,而在第二个版本中,您将相同的指针推送到 pvectorAobjectAsize
  • 抱歉,我编辑了问题。

标签: c++ pointers vector stl push-back


【解决方案1】:

阅读std::vector::push_back的文档

首先是描述:

在向量的最后一个元素之后添加一个新元素。 val 的内容被复制(或移动)到新元素。

这会有效地将容器大小增加一,这会导致自动重新分配已分配的存储空间,当且仅当新向量大小超过当前向量容量时。

然后关于迭代器的有效性:

如果发生重新分配,与容器相关的所有迭代器、指针和引用都将失效

因此,当您将对象添加到向量时,指向该向量中对象的所有指针都可能变得无效 - 除非您保证向量有足够的 capacitystd::vector::reserve

无效意味着指针不再指向一个有效的对象并且取消引用它会有未定义的行为。

在后面的代码中,在存储了指针之后,您永远不会向指向的向量添加对象,因此指针是有效的。

【讨论】:

    【解决方案2】:

    当您使用push_back 将元素添加到向量时,它会被复制到向量中。这意味着,在第一个示例中,vectorA 包含objectA 的副本,而objectA 超出范围并在右大括号后立即被删除。这意味着pvectorA 中的指针指向的地址不再一定包含objectA

    您的第二个示例不应该工作,因为objectA 在第一个循环之后已经超出范围,所以我无法帮助您。

    【讨论】:

      【解决方案3】:

      当您将元素推入vectorA 时,它偶尔会变满,并且必须将其对象重新定位到更大的内存块。这将改变每个元素的地址。

      如果pvectorA 存储了指向元素原始位置的指针,那么即使vectorA 元素被移动到新位置,这些指针仍将指向旧位置。

      【讨论】:

        【解决方案4】:

        当您执行vectorA.push_back 时,您可能会导致该向量重新分配自身以增加容量,这意味着它的所有内容都会被移动,这意味着您保存的任何指向其内容的指针都将无效。

        也许您想重新考虑存储指向向量元素的指针的整个想法。

        如果你不能放弃存储指针的整个想法,但你提前知道所需的大小,你可以在循环之前使用reserve:

        vectorA.reserve(size);
        for(i=0; i<size; i++){
            //create objectA here
            vectorA.push_back(objectA);
            pvectorA.push_back(&vectorA[i]);
        }
        

        在此版本中,指针在您进一步增大 vectorA 或销毁它之前都是有效的。

        【讨论】:

          【解决方案5】:

          这是因为向量在超出当前容量时会重新分配其内部存储空间;重新分配后,元素的地址可能发生了变化。

          您可以通过预先预留足够大的存储空间来避免重新分配:

          vectorA.reserve(size);
          //vectorB.reserve(size); // this would not hurt either
          for(i=0; i<size; i++){
            //create objectA here
            vectorA.push_back(objectA);
            pvectorA.push_back(&vectorA[i]);
          }
          

          最后一点:如果您可以使用 C++11,emplace_back 会在适当位置构造您的对象,因此无需复制。

          【讨论】:

            【解决方案6】:

            如果您想要一个具有恒定时间插入的序列容器并且不使指向其他元素的迭代器失效,请使用 std::list。但是请注意,std::vector 通常是使用最快的数据结构(在某些情况下,您需要预先排序的 std::vector)。一个突出的原因是数组比缓存更友好。树或链表。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-06-05
              • 2014-09-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多