STL之迭代器&&迭代器失效

Dear 丶 2022-05-17 12:46 497阅读 0赞

1.说说设计模式?(迭代器模式)

  1. 迭代器模式作为STL的六大组件之一,通俗来讲,它就是用来遍历容器的,对容器进行一定的操作。我们通常使用的容器vectorlistmapsetmultimapmultisetdeque,内部是实现有顺序表、链表、红黑树。如果我们遍历这些容器就要明白它们的底层构造,相当不方便。iterator被定义出来就是不需要了解这些容器的底层实现,来访问修改容器中的数据。也就是说:**iterator模式是一种运用于聚合对象的一种模式。通过iterator模式,我们可以在不知道对象内部表示的情况下,按照iterator提供的方法访问聚合对象中的各个元素。**

作用能够让迭代器与算法互不干扰的相互发展,最后又能无间隙的粘合在一起。

  1. vector<int> v1{ 1, 2, 3, 4, 5, 6 };
  2. vector<int>::iterator iter = v1.begin();
  3. while (iter!= v1.end())
  4. {
  5. *iter = " "; //不能对其赋值
  6. /*cout << *iter << " ";
  7. ++iter;*/
  8. }

2.迭代器失效的原理及解决办法

1. 对于序列式容器(vector,deque),删除当前的iterator会使后面所有的元素的迭代器都失效。因为数组式容器都是使用的连续分配的内存,删除一个元素会使后面的元素都往前移动一个位置,所以使用erase函数删除数据时,iterator++指向的是未知的区域。 所以删除一个数据后,其他数据的地址发生了变化,之前获取的迭代器根据原有的信息就访问不到正确的数据。只要改一下代码使其返回下一个有效的迭代器就可以了。

  1. for (iter = container.begin(); iter != container.end();)
  2. {
  3. if (*iter % 2 == 0)
  4. iter = container.erase(iter); //erase的返回值是删除元素下一个元素的迭代器
  5. else{
  6. iter++;
  7. }
  8. }

2. 对于关联容器(map、set、multiset、multimap),删除当前的iterator只会使当前的迭代器失效,只要在删除时,递增当前的iterator即可。这是因为map之类的容器是由红黑树实现的,对红黑树插入或者删除结点不会对其他结点造成影响。erase迭代器,只是被删除的迭代器失效,返回为void,只需要采用erase(it++)的方式删除迭代器。 map.erase(iter)之后,iter就已经失效了,所以iter无法自增,即iter++就会出bug.解决方案,就是在iter失效之前,先自增。

  1. 擦除操作引发迭代器失效
  2. for (iter = map.begin(); iter != map1.end(); )
  3. {
  4. int Key = iter->first;
  5. string strValue = iter->second;
  6. if (Key % 2 == 0)
  7. {
  8. //map<int, string>::iterator tmpIter = iter;
  9. //iter++;
  10. //map1.erase(tmpIter);
  11. map1.erase(iter++); //先把iter传值到erase里面,然后iter自增,然后执行erase
  12. }
  13. else
  14. {
  15. iter ++;
  16. }
  17. }
  18. map<int, string>::iterator tmpIter =iter;
  19. iter++;
  20. dataMap.erase(tmpIter);
  21. //这几句的意思是,先保留要删除的节点迭代器,再让iter向下一个有意义的节点,然后删除节点。
  22. 所以这个操作结束后iter指向的是下一个有意义的节点,没有失效。

3.容器list是使用不连续分配的内存,在调用erase函数进行删除某一个结点时,导致这个结点的迭代器失效。因为在将结点删除以后,没有改变当前迭代器的指向。第一种:为erase函数设置一个返回值,返回当前结点的下一个结点的迭代器,即 iterator iter = erase (iter)。第二种:给erase传值时为 erase(iter++);这是因为当把当前位置传递给函数之后,自动指向下一个位置。

  1. list<int> l1{1, 2, 3, 4, 5};
  2. list<int>::iterator iter = l1.begin();
  3. while(iter != l1.end())
  4. {
  5. if(*iter % 2 == 0)
  6. {
  7. //iter = l1.erase(iter); //返回删除元素的下一个迭代器
  8. l1.erase(iter++);
  9. }
  10. else
  11. {
  12. iter++;
  13. }
  14. }

4.对于vector和string,如果容器内存被重新分配,插入元素后,iterators,pointers,references失效;如果没有重新分配,那么插入点之前的iterator有效,插入点之后的iterator失效。对于deque,如果插入点位于除front和back的其它位置,iterators,pointers,references失效;当我们插入元素到front和back时,deque的迭代器失效,但reference和pointers有效。


发表评论

表情:
评论列表 (有 0 条评论,497人围观)

还没有评论,来说两句吧...

相关阅读

    相关 520-C++STL()

    const\_iterator:常量的正向迭代器,只能读,而不能写了 iterator:普通的正向迭代器,从第一个访问到最后一个,可以更改元素值 reverse\_it

    相关 c++ stl 浅析

    1.c++ stl之迭代器(iterator) 迭代器是一个可遍历stl容器内全部或者部分元素的一个类(注意这里是类)。一个迭代器用来指出容器中的一个特定位置,也就是指

    相关 STL

    什么是迭代器 迭代器是STL中行为类似指针的设计模式,它可以提供了一种对容器中的对象的访问方法;并且它没有暴露容器中内部的表述方式。 例如STL中的map和set,它

    相关 STL&&失效

    1.说说设计模式?(迭代器模式)         迭代器模式作为STL的六大组件之一,通俗来讲,它就是用来遍历容器的,对容器进行一定的操作。我们通常使用的容器vector