我发现这个C ++代码:
vector<int> a;
a.push_back(1);
a.push_back(2);
vector<int>::iterator it = a.begin();
a.push_back(4);
cout << *it;
打印一些大的随机数;但如果你在第3行和第4行之间添加a.push_back(3)
,它将打印1.你能解释一下吗?
答案 0 :(得分:28)
用更谨慎的措辞编辑
是的,调整向量大小可能会使指向向量的所有迭代器无效。
通过在内部分配存储数据的数组来实现向量。当向量增长时,该数组可能会用完空间,当它出现时,向量会分配一个更大的新数组,将数据复制到该数组,然后删除旧数组。
因此,指向旧内存的旧迭代器不再有效。
但是,如果向量向下(例如通过pop_back()
),则使用相同的数组。数组永远不会自动缩小尺寸。
避免这种重新分配(和指针失效)的一种方法是首先调用vector::reserve()
,留出足够的空间以便不需要复制。在您的情况下,如果您在第一次a.reserve(3)
操作之前调用push_back()
,那么内部数组将足够大,以便可以执行push_back
而无需重新分配数组,并且所以你的迭代器将保持有效。
答案 1 :(得分:7)
向量迭代器仅在向量执行重新分配时失效。
对push_back(4)
的调用导致向量分配新的内存块 - 这是导致迭代器的原因失效。当您还使用push_back(3)
时,不会对push_back(4)
执行重新分配,因此迭代器仍然有效。
答案 2 :(得分:3)
是的,任何可能改变向量大小的操作都会使迭代器失效。
修改:包括减少容器大小的操作(例如erase()
,resize()
)。 erase()
不会使所有迭代器无效,但它会使引用已擦除元素之后的任何点的任何迭代器无效。 resize()
是根据insert()
和erase()
定义的,因此具有相同的潜力。
答案 3 :(得分: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上的任何操作。另一方面,表达式(* it)不断变化:首先它返回0,然后是1,然后它有未定义的行为......
一般来说,人们宁愿谈论第二个要求,而使迭代器无效只是意味着(*它)可能不会产生与以前相同的结果。
既然如此,有几种方法可以使Vector上的迭代器无效(实际上,它是STL不太稳定的结构)。
在添加元素期间:
insert
。插入元素会使指向当前位置和所有后续位置的迭代器无效,因为元素向向量的一端移向向量的末尾。删除元素期间:
(1)std :: vector的内部结构是T的数组,这是因为与C程序兼容(使用&amp; myVector.front()作为数组的地址),因为它保证连续性和最小空间开销(即,向量自身数据占用的空间量与对象占用的空间量)
在任何时候,您都可以使用.capacity()方法知道矢量可以容纳多少个对象。
如果要插入对象且向量没有必要的容量,则会触发对.reserve(size_t)方法的调用。如果所需的项目数量优于当前容量,则此方法会触发重新分配。
然后向量分配一个新的元素数组(其大小通常为2 * n + 1,其中n是当前容量),将当前数组的元素复制到新数组,丢弃当前数组。
因为它丢弃了当前数组,所以迭代器无效,因为向量迭代器通常是简单的指针(为了提高效率)。
请注意,如果迭代器实现为:对向量的引用+计数,并且解除引用实际上是*(&amp; m_vector.front()+ n)重新分配不会使它们失效...但它们会更少高效。
(2)缩小到适合:警告,这会触发元素的COPY并使迭代器无效。
// myVector has 10 elements, but myVector.capacity() == 1000
myVector.swap(std::vector<int>(myVector));
它首先创建一个临时向量,它将根据需要分配尽可能多的内存(最小值取决于库),并复制myVector的元素。然后交换操作从myVector和此副本交换缓冲区,因此myVector现在支持一个具有所需最小内存量的缓冲区。在操作结束时,临时被破坏并且它保存的内存被释放。
答案 4 :(得分:0)
为了将来参考,像这样的所有STL类别的花絮都在SGI的网站上:http://www.sgi.com/tech/stl/Vector.html
如果在添加或删除集合后需要迭代器保持有效,请查看另一种集合,如列表。
最好的办法是从集合中识别出你想要的特征矩阵(随机访问等),然后选择合适的容器。
有关起点,请参阅有关Standard_Template_Library容器的维基百科文章。如果您有现金,我强烈推荐Scott Meyer的“有效STL:50种改进您使用标准模板库的具体方法”。
对于缺乏支持链接的抱歉,我在这里是一个新手,并且缺少与多个人发布此信息的声誉。