• C++ STL --- vector之迭代器失效


    目录

    1.什么是迭代器失效?

      (1)文字阐述迭代器失效 

      (2)举例阐述迭代器失效

    2.vector哪些操作会导致迭代器失效?

    3.如何避免迭代器失效?


            在上一篇关于vector用法的博客中,曾提到过迭代器失效这个话题,但是因为那篇文章主要是用来展示函数用法的,所以单独来谈一下迭代器失效。

            这篇文章的要点只有三点:1.什么是迭代器失效? 2.vector哪些操作会导致迭代器失效? 3.如何避免迭代器失效?

    1.什么是迭代器失效?

      (1)文字阐述迭代器失效 

            [1]迭代器的本质就是指针,迭代器失效就是指针失效。

            [2]指针失效:指针指向的空间是非法的。

            [3]指针指向非法空间:指向了被释放的空间 或者 越界访问 。

            是不是很简单,只需要三句话就可以简单阐述迭代器失效。

      (2)举例阐述迭代器失效

            下面来看一个例子更好的理解迭代器失效。

            代码一:这段代码编译的时候就已经报错了,所以为大家截图了调试时的监视窗口。

            原因:it指向初始空间的首元素,尾插元素时空间不足,开辟更大的新空间存储元素,释放旧空间,但此时it仍旧指向已经被释放的旧空间,成为了野指针。在循环中试图对野指针进行解引用导致程序崩溃。

    1. //代码一
    2. #include "iostream"
    3. #include "vector"
    4. using namespace std;
    5. void Test() {
    6. vector<int> v{ 1,2,3,4 };
    7. //指向当前空间的首元素
    8. auto it = v.begin();
    9. //开辟新空间,拷贝元素释放旧空间
    10. //此时it仍旧指向旧空间
    11. v.push_back(5);
    12. while (it != v.end()) {
    13. cout << *it;
    14. it++;
    15. }
    16. }
    17. int main() {
    18. Test();
    19. }

            调试代码时的 监视窗口:在监视窗口中可以看到,初始容量是4,尾插时进行了扩容,这也就导致了it成为野指针

     

            相信通过这个例子大家已经更好的理解了迭代器失效。

    2.vector哪些操作会导致迭代器失效?

            a.所有可能会引起扩容的操作都可能会导致迭代器失效。如:resize、reserve、insert、assign、push_back等

            这一点在举例子时已经证明过了,这里就不再赘述了。

            b.指定位置的删除操作--erase。这一点比较难理解。

            首先要知道erase(iterator pos)函数的返回值是被删除元素后一位元素的迭代器。当删除元素后,pos位置之后的元素会往前搬移,没有导致底层空间改变。理论上来说是不是觉得这个函数并不会导致迭代器失效?

            但是:如果pos元素刚好是最后一个元素,删完后pos就刚好是end()的位置,而end()位置并没有元素,那么一旦试图解引用pos就会崩溃。因此vs编译器觉得这样的操作不安全,vs就认为当你使用erase删除了一个元素后,该位置的迭代器就应该按失效处理,不要再使用了。

    1. //代码二
    2. #include "iostream"
    3. #include "vector"
    4. #include "algorithm"
    5. using namespace std;
    6. void Test() {
    7. vector<int> v{ 1,2,3,4 ,5,6,7,8,9,10};
    8. auto it = v.begin();
    9. //删除偶数
    10. while (it != v.end()) {
    11. if (*it % 2 == 0)
    12. v.erase(it);
    13. else
    14. it++;
    15. }
    16. }
    17. int main() {
    18. Test();
    19. }

    3.如何避免迭代器失效?

            解决办法简单粗暴:在所有可能导致迭代器失效的操作之后,如果要使用迭代器,在使用前重新赋值,使其指向新空间。

            既然迭代器可能失效,那么我就在使用前重新赋值,让其指向合法的空间再使用。

            现在来把代码一和二做一点小小的改动,让它们变得安全。

            代码三:将代码一和二放在同一段代码中,在使用之前对其重新赋值。

            使用erase函数后,就用它的返回值重新对迭代器赋值,使它变得安全。

    1. //代码三
    2. #include "iostream"
    3. #include "vector"
    4. #include "algorithm"
    5. using namespace std;
    6. void Test1() {
    7. vector<int> v{ 1,2,3,4 };
    8. auto it = v.begin();
    9. v.push_back(5);
    10. //使用迭代器前对它重新赋值
    11. it = v.begin();
    12. while (it != v.end()) {
    13. cout << *it;
    14. it++;
    15. }
    16. }
    17. void Test2() {
    18. vector<int> v{ 1,2,3,4 ,5,6,7,8,9,10 };
    19. auto it = v.begin();
    20. //删除偶数
    21. while (it != v.end()) {
    22. if (*it % 2 == 0)
    23. //因为erase函数返回值是被删除元素后一位元素的迭代器
    24. //用它的返回值对it进行重新赋值
    25. it = v.erase(it);
    26. else
    27. it++;
    28. }
    29. }
    30. int main() {
    31. Test1();
    32. Test2();
    33. }

  • 相关阅读:
    JS逆向之巨量算数signature与data解密
    2022一带一路暨金砖国家技能发展与技术创新大赛小程序应用开发国内赛-二等奖经验分享
    尚未解决的难题
    怎么设置 idea terminal 窗口的编码格式
    SQL第三次上机作业
    Linux基本指令(中)
    简述结构化范型和面向对象范型的要点,并分析它们的优缺点。
    前端周刊第三十七期
    LLm微调使用的数据集
    element ui 下拉框 选择月份和天数
  • 原文地址:https://blog.csdn.net/weixin_57761086/article/details/126571033