所有的标准库容器都可以使用迭代器,迭代器的主要目的是用来遍历容器的,虽然每个容器的的底层的实现不一样,但对于迭代器来说,对容器的遍历都是一样的,都封装到迭代器的函数中。每个容器都有自己的迭代器的实现,所以在外部开来,操作都是一样的。泛型算法的接受对象都是迭代器。
类似于指针,迭代器也提供了对对象的间接访问。通过解引用迭代器,就能访问容器中的元素。迭代器也能从一个元素移动到另一个元素,可以通过重载++运算符来实现。
迭代器的有效性
迭代器也分有效和无效,有效的迭代器指向一个元素或者执行尾元素的下一位置。其他其他情况都是属于无效。
迭代器的失效:当容器元素的个数发生改变的时候就发生迭代器失效,主要原因是当插入或删除一个元素的时候,使整个容器的存储顺序发生改变,而迭代器实质上是指向每个元素的,如果元素的顺序改变,那就要更新迭代器,之前的迭代器指向的内容可能会发生改变,发生了改变,就认为该迭代器失效了。
总结一下,顺序迭代器失效的情况:
vector:
①当使用erase函数的时候,从插入元素位置开始之后的迭代器都失效,因为erase函数的底层实现是,将final指针减一,如果是要删除最后一个元素,final指针直接减一,不是的话,就将之后的元素直接覆盖要删除的元素,其余的元素直接拷贝过来,最后final指针减一,在析构final指针指向的空间。所以从插入元素位置开始之后的迭代器都失效。
②使用insert插入一个元素的时候,插入元素之前的迭代器不会失效,而插入元素之后的迭代器会失效,这和erase函数的道理是一样的。
③使用push_back函数之后,end()函数返回的迭代器肯定会发生失效;
④如果插入后发生了扩容,则整个容器的迭代器都会失效。因为要重新调整容器的空间,开辟新的内存。之前迭代器指向的位置,和扩容后的位置肯定是一样的
deque:
①在deque容器首部或者尾部插入元素不会使得任何迭代器失效。//通过vs2012测试不管前端插入还是后端插入,都会使迭代器 失效
②在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。
③在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。
因为deque的底层数据结构是一个动态二维数组,虽说一维不是连续的,但是二维却是连续的,插入或者删除都会有元素的移动,这和vector一样。
list:
①插入操作(insert)和接合操作(splice)不会造成原有的list迭代器失效,因为,list是不连续的,每一个元素的迭代器的指向都是互不干扰的,即使是插入了或删除了一个元素,其他元素的指向都不会变,这在vector中是不成立的,因为vector的插入操作可能造成记忆体重新配置,导致所有的迭代器全部失效。
②list的删除操作(erase)也只有指向被删除元素的那个迭代器失效,其他迭代器不受影响。
使用迭代器:
通过begin函数来指向容器的首元素,end函数来指向尾元素后一个位置。eg:
vector<int > vec(10,0);//容器里有10个元素,且都初始化为0
auto it=vec.begin();
for(;it!=vec.end();++it)
{
cout<<*it<<endl;
}
则将会输出10个0;
如果容器为空的话,begin和end返回的是同一个迭代器,都是尾后迭代器。所以在比较两个迭代器的时候通常要进行判空的操作;
迭代器都会支持一些运算符的使用,在遍历容器的时候,就需要比较两个迭代器是否相同,所以必须要重载==和!=运算符,如果两个迭代器指向的元素相同或者是同一容器的尾后迭代器,则它们相等,否则不相等。
同时,我们也可以5通过++运算符来实现从一个元素移动到另一个元素上。