指针向量中的 C++ 垃圾值

c++ garbage values in vector of pointer

当我这样做时:

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]);
}

一切都很好。为什么会这样?

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

你的第二个例子不应该工作,因为 objectA 在第一个循环后超出了范围,所以我无法帮助你。

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

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

阅读 std::vector::push_back

的文档

首先是描述:

Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.

This effectively increases the container size by one, which causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.

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

If a reallocation happens, all iterators, pointers and references related to the container are invalidated.

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

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

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

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

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

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

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

在此版本中,指针一直有效,直到您进一步增大 vectorA 或将其销毁。

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

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

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 就地构造您的对象,因此无需复制。

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