我有两个关于迭代器的问题。
我认为一旦你定义了一个STL容器的迭代器,例如向量或列表,如果你向容器添加元素,那么这些迭代器将无法访问它们。但是下面的代码定义了五个元素的列表,然后在每个循环迭代中添加另一个元素并导致无限循环:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> ls;
for(int i = 0; i < 5; i++)
{
ls.push_back(i);
}
int idx = 0;
for(list<int>::iterator iter = ls.begin(); iter != ls.end(); iter++)
{
cout << "idx: " << idx << ", *iter: " << *iter << endl;
ls.push_back(7);
idx++;
}
}
但是,对矢量执行相同操作会导致错误:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec;
for(int i = 0; i < 5; i++)
{
vec.push_back(i);
}
int idx = 0;
for(vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++)
{
cout << "idx: " << idx << ", *iter: " << *iter << endl;
vec.push_back(7);
idx++;
}
}
我认为当向量容器必须调整大小时,它会以2的幂为单位并且位于新的内存区域,这就是为什么在添加时不应该为向量定义迭代器的原因它的元素(因为迭代器不会传递到新的内存位置)。例如,我认为在调用push_back函数之后,包含16个元素的向量将被分配32个元素的空间,并且将重新定位整个向量。但是,以下代码没有发生这种情况。我错了吗?
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec;
for(int i = 0; i < 4; i++)
{
vec.push_back(i);
cout << "address of vec: " << &vec << ", capacity: " << vec.capacity() << endl;
}
for(int i = 0; i < 20; i++)
{
vec.push_back(i);
cout << "address of vec: " << &vec << ", capacity: " << vec.capacity() << endl;
}
}
答案 0 :(得分:3)
不同容器的迭代器具有不同的属性。 Here are the iterator invalidation rules
列表循环:当您按下list
时,所有以前的迭代器仍然有效。如果你每次迭代前进一个,你也永远不会达到目的,显然你也会添加一个新元素。
向量循环:对于向量,一旦push_back
导致新大小超过旧容量,则迭代器无效。一旦发生这种情况,使用iter
是未定义的行为(您可能会崩溃)。
我认为当必须调整矢量容器大小时,它会这样做 在2的幂,并位于一个新的记忆区域
标准未指明。当大小超过旧容量时,C ++标准库的某些实现会使向量的容量加倍,而其他实现则以不同的速率增长。
答案 1 :(得分:0)
第一个问题的答案包含在你的第二个问题中。
至于第二个问题,那么实现定义了向量如何分配内存。每次耗尽时,没有必要将内存的大小加倍。
答案 2 :(得分:0)
对于迭代器的有效性以及对元素的指针/引用,不同的容器通常有不同的保证:
std::list<T>
,元素的迭代器和指针/引用保持有效,直到相应的节点被删除或std::list<T>
存在。std::vector<T>
,有效性更复杂:
std::vector<T>
需要调整其内部缓冲区大小时,即插入超出容量时,所有迭代器都无效。当超出容量并分配多少内存取决于实现(唯一的要求是容量呈指数级增长,2倍是合理的选择,但还有很多其他选择)。std::vector<T>
所有迭代器时保持有效,除非需要重新分配。std::vector<T>
擦除点之后的所有迭代器时无效。其他容器有不同的有效性约束(例如std::deque<T>
使迭代器无效,但可以使指针/引用保持有效)。