是否调整矢量迭代器失效?(Does resizing a vector invalidate ite

2019-09-01 06:40发布

我发现,这个C ++代码:

vector<int> a;
a.push_back(1);
a.push_back(2);
vector<int>::iterator it = a.begin();
a.push_back(4);
cout << *it;

打印一些大的随机数; 但如果添加a.push_back(3)第三和第四线之间,将打印1.你能解释一下?

Answer 1:

用更谨慎的措辞编辑

是的,调整向量可能指向无效到载体所有迭代器。

该载体通过在内部分配,其中的数据存储阵列来实现。 当向量的增长,该阵列可能会用完的空间,当它的载体转移到该分配一个新的,更大的,阵列,复制数据,然后删除旧的阵列。

所以,你的旧迭代器,这点到旧的内存,不再有效。 如果载体是向下调整大小(由例如pop_back()然而,使用相同的数组。 阵列不会自动小型化。

为了避免这种重新分配(和指针失效)的一种方法是调用vector::reserve()第一,留出足够的空间,这种复制是没有必要的。 在你的情况,如果你叫a.reserve(3)第一之前push_back()操作,则内部数组将是足够大了push_back的可能,而无需重新分配阵列来进行,所以你的迭代器将保持有效。



Answer 2:

当该矢量进行重新分配向量迭代仅无效。

调用push_back(4)是造成分配的内存块的新载体-这是什么原因导致你的迭代器变得无效。 当您还使用push_back(3)没有重新分配用于执行push_back(4)因此,迭代器仍然有效。



Answer 3:

是的,这可能会改变向量的大小的任何行动可以迭代器失效。

编辑:这包括操作(例如, erase() resize()减少容器的大小。 erase()并不能否定所有迭代器,但它确实无效提及任何点擦除单元(一个或多个)之后的任何迭代器。 resize()在以下方面被定义insert()erase()因此具有相同的电位。



Answer 4:

对于迭代器失效的规则是具体到一个容器中。

现在失效可能有2个含义有一个向量:

  1. 无效=所限定的范围之外的点[开始,结束]
  2. 无效=指向一个不同的对象从原来的一个

正如你所看到的,第二个是要严格得多:

std::vector<int> myVector;
myVector.push_back(0);
myVector.push_back(1);

std::vector<int>::iterator it = myVector.begin(); // it points to 0
myVector.erase(it); // it points to 1
myVector.erase(it); // it == myVector.end()

在这种情况下,它是“有效”的,因为它总是在包容范围[开始,结束],因此可以安全地用于对myVector任何操作。 在另一方面表达式(*吧)不断变化的:首先,它返回0,1,那么它是未定义行为...

在一般情况下,人们宁愿谈论的第二个要求,无效的迭代器只是意味着(*吧)可能不会像以前那样产生相同的结果。


现在,这是说,有几种方法可以在矢量无效的迭代器(事实上,它是STL的不太稳定的结构)。

在元素的补充:

  • 这可能会引发再分配 (1)如果myVector.size()== myVector.capacity(),因为进行这样的检查容易出错,我们通常认为,任何另外将无效的迭代器
  • 如果你想成为“挑剔”,并知道该重新分配未被触发,那么你仍然担心insert 。 插入元件无效指向这个当前位置的迭代器,并且由于元件的所有后续那些错开朝向矢量的末端的一个步骤。

在消除元件:

  • 有没有重新分配,即使缓冲区现在远大于需要。 这是可能迫使这虽然,使用收缩配合成语(2)。
  • 所有指向过去删除的元素迭代器失效。 特别是,先前的“结束”现在的迭代器超出[开始,结束]范围,不能STL算法例如内安全地使用。

(1)一个std ::载体的内部结构为T的阵列,这是由于用于与C-程序(myVector.front()作为数组的地址使用&)的相容性和,因为它保证连续性和最小空间开销(即,由矢量自己的数据VS的空间由物体占用的量采取的空间的量)

在任何时候,你就可以知道一个向量可以有多少个对象持有使用.capacity()方法。

当你要插入的对象和载体不具备必要的能力,被触发的.reserve(为size_t)方法的调用。 该方法,如果需要的物品的数量是优于当前容量,触发重新分配

该载体然后分配元件的新阵列(其大小通常为2 * N + 1,其中n是当前容量),将当前阵列到新数组的元素,丢弃当前数组。

因为它丢弃当前阵列,你的迭代器被无效作为向量迭代器通常简单的指针(对于效率)。

需要注意的是,如果迭代器是为实现:到矢量+计数的参考,并取消引用竟是*(&m_vector.front()+ n)的重新分配将不会使它们无效......但他们是效率较低。

(2)收缩以适应:警告,这触发了对元素的副本和无效迭代器。

// myVector has 10 elements, but myVector.capacity() == 1000
myVector.swap(std::vector<int>(myVector));

它首先创建的临时载体,如需要(以取决于库最小),这将仅分配尽可能多的内存,并复制myVector的元素。 然后交换操作交换从myVector缓冲器和该副本,并且因此myVector现在hols用的必要的最小内存量的缓冲器。 在操作结束时,临时被破坏和存储其持有释放。



Answer 5:

对于未来的参考,所有的STL各种这样的花絮是在SGI的网站: http://www.sgi.com/tech/stl/Vector.html

如果您需要迭代留下您添加或删除集合后有效,看看其他类型的集合,就像一个列表。

虽则做的最好的事情是确定出你从一个集合(随机访问等)想要的功能矩阵,然后挑选合适的容器。

见起点上Standard_Template_Library集装箱维基百科的文章。 如果你有现金,我强烈建议斯科特·梅耶的“有效STL:50层具体的方法来提高你的标准模板库的使用”。

由于缺乏配套环节的道歉,在这里我是新手,缺乏信誉与多个张贴此。



文章来源: Does resizing a vector invalidate iterators?