C++ Primer:vector删除元素时迭代器失效问题

淩亂°似流年 2023-05-28 06:45 114阅读 0赞

提示:以下所有程序是使用MinGW编译运行的。若使用VS的MSVC运行,程序会报错,因为MSVC无法解引用失效迭代器或尾后迭代器。


1. 删除尾元素

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. //输出
  5. void show(vector<int> &v);
  6. //迭代器
  7. vector<int>::iterator i1, i2, i3, i4;
  8. int main()
  9. {
  10. vector<int> vi{1, 2, 3};
  11. //迭代器
  12. i1 = vi.begin();
  13. i2 = vi.begin() + 1;
  14. i3 = vi.begin() + 2;
  15. i4 = vi.end();
  16. //输出
  17. show(vi);
  18. //在末尾删除
  19. vi.pop_back();
  20. //输出
  21. show(vi);
  22. return 0;
  23. }
  24. void show(vector<int> &v)
  25. {
  26. cout << "vector: ";
  27. for (auto &a : v)
  28. {
  29. cout << a << "(" << &a << ")"
  30. << "\t";
  31. }
  32. cout << "\ni1~i4: ";
  33. for (auto a = i1; a != i4; ++a)
  34. {
  35. cout << *a << "\t\t";
  36. }
  37. cout << "\niterate: ";
  38. cout << *i1 << "(" << &(*i1) << ")"
  39. << "\t";
  40. cout << *i2 << "(" << &(*i2) << ")"
  41. << "\t";
  42. cout << *i3 << "(" << &(*i3) << ")"
  43. << "\t";
  44. cout << *i4 << "(" << &(*i4) << ")"
  45. << "\t"; //解引用尾后迭代器的行为是未定义的
  46. cout << endl
  47. << endl;
  48. }

运行结果

删除元素前后比较

分析:

  1. 删除尾元素后,vector只剩2个元素,但从i1遍历到i4时依然读出3个元素,说明i3和i4已失效。
  2. 删除元素前i3指向vi的第3个元素,删除元素后i3指向vi的尾后元素,也说明i3已失效。
  3. 删除元素前i4指向vi的尾后元素,删除元素后i3指向未知内存区域,也说明i4已失效。

2. 删除中间元素

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. //输出
  5. void show(vector<int> &v);
  6. //迭代器
  7. vector<int>::iterator i1, i2, i3, i4;
  8. int main()
  9. {
  10. vector<int> vi{1, 2, 3};
  11. //迭代器
  12. i1 = vi.begin();
  13. i2 = vi.begin() + 1;
  14. i3 = vi.begin() + 2;
  15. i4 = vi.end();
  16. //输出
  17. show(vi);
  18. //删除第2个元素
  19. vi.erase(i2);
  20. //输出
  21. show(vi);
  22. return 0;
  23. }
  24. void show(vector<int> &v)
  25. {
  26. cout << "vector: ";
  27. for (auto &a : v)
  28. {
  29. cout << a << "(" << &a << ")"
  30. << "\t";
  31. }
  32. cout << "\ni1~i4: ";
  33. for (auto a = i1; a != i4; ++a)
  34. {
  35. cout << *a << "\t\t";
  36. }
  37. cout << "\niterate: ";
  38. cout << *i1 << "(" << &(*i1) << ")"
  39. << "\t";
  40. cout << *i2 << "(" << &(*i2) << ")"
  41. << "\t";
  42. cout << *i3 << "(" << &(*i3) << ")"
  43. << "\t";
  44. cout << *i4 << "(" << &(*i4) << ")" //解引用尾后迭代器的行为是未定义的
  45. << "\t";
  46. cout << endl
  47. << endl;
  48. }

运行结果

删除元素前后比较

分析:

  1. 删除尾元素后,vector只剩2个元素,但从i1遍历到i4时依然读出3个元素,说明i3和i4已失效。
  2. 删除元素前后,*i2从2变成3,说明i2已失效。

3. 删除首元素

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. //输出
  5. void show(vector<int> &v);
  6. //迭代器
  7. vector<int>::iterator i1, i2, i3, i4;
  8. int main()
  9. {
  10. vector<int> vi{1, 2, 3};
  11. //迭代器
  12. i1 = vi.begin();
  13. i2 = vi.begin() + 1;
  14. i3 = vi.begin() + 2;
  15. i4 = vi.end();
  16. //输出
  17. show(vi);
  18. //删除第1个元素
  19. vi.erase(i1);
  20. //输出
  21. show(vi);
  22. return 0;
  23. }
  24. void show(vector<int> &v)
  25. {
  26. cout << "vector: ";
  27. for (auto &a : v)
  28. {
  29. cout << a << "(" << &a << ")"
  30. << "\t";
  31. }
  32. cout << "\ni1~i4: ";
  33. for (auto a = i1; a != i4; ++a)
  34. {
  35. cout << *a << "\t\t";
  36. }
  37. cout << "\niterate: ";
  38. cout << *i1 << "(" << &(*i1) << ")"
  39. << "\t";
  40. cout << *i2 << "(" << &(*i2) << ")"
  41. << "\t";
  42. cout << *i3 << "(" << &(*i3) << ")"
  43. << "\t";
  44. cout << *i4 << "(" << &(*i4) << ")" //解引用尾后迭代器的行为是未定义的
  45. << "\t";
  46. cout << endl
  47. << endl;
  48. }

运行结果

删除元素前后比较

分析:

  1. 删除尾元素后,vector只剩2个元素,但从i1遍历到i4时依然读出3个元素,说明i3和i4已失效。
  2. 删除元素前后,*i2从2变成3,说明i2已失效。
  3. 删除元素前后,*i1从1变成2,说明i1已失效。

4. 总结

  1. 在vector删除元素时,若迭代器指向删除元素之前的元素,则该迭代器仍有效。若迭代器指向被删元素及其之后的元素,则该迭代器将会失效。
  2. 在添加、删除、修改元素时,尽量直接使用begin()和end(),或者使用insert()和erase()更新相应的迭代器,避免使用迭代器的中间量。

    vector vi;
    //i保存的是vi的迭代器,有时操作后(如添加元素,删除元素)不确定i是否有效
    auto i=vi.begin()+n;
    vi.erase(i);
    //尽量直接使用begin()和end(),避免使用中间量i
    vi.erase(vi.begin()+n);
    //下面的表达式更好,因为它会自动更新i
    i=vi.erase(i);

发表评论

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

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

相关阅读

    相关 C++】list失效问题

    对于迭代器,我们可以暂时将它理解为指针。 迭代器失效指迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时

    相关 STL之&&失效

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