zoukankan      html  css  js  c++  java
  • 迭代器失效问题

    话说回来,今天 ymx 发了个关于 std::list 迭代器失效的问题,正好也让我对这方面的芝士有所了解,故作文以记之((

    首先先贴一张 C++ reference 里的图:

    我们知道 C++ STL 中的容器大致可分为四类,序列型(如 vector,deque,queue)、关联型(set,map,multiset)和链表型(list,forward_list),这三种类型的容器迭代器失效的情况是不同的,因此这里会对其一一进行阐述:

    1. 序列型容器

    序列型容器的特点是它内存分配是一段连续的区间,也就是说,当你删除一个元素后会导致后面的元素全部向前移动一格,使得后面元素的迭代器全部失效,因此删除 vector 中的元素不能这么写:

    for(vector<int>::iterator it=vec.begin();it!=vec.end();it++){
        if((*it)>100) vec.erase(it);
    }
    

    也不能这么写:

    for(vector<int>::iterator it=vec.begin();it!=vec.end();it++){
        if((*it)>100) vec.erase(it++);
    }
    

    一个解决办法是:利用 vector 类型中 erase 函数的返回值找出下一个合法的地址,即:

    for(vector<int>::iterator it=vec.begin();it!=vec.end();){
        if((*it)>100) it=vec.erase(it);
        else ++it;
    }
    

    此外,根据 vector 自动伸长的原理(如果不清楚参见 THUSC2021 试机赛 T2,如果没参加过 THUSC2021……那恐怕我也没办法了),若删除一个元素后 vector 的长度变为某个 (2^k-1(kinmathbb{Z})),那么 vector 分配的内存大小将会减半,导致 vector 内部全部重构,此时整个 vector 的迭代器都会失效。

    2. 关联型容器

    与序列型容器不同的是,关联型容器内部是二叉树或红黑树,因此它们的内存分配是没有规律的,删除一个元素后只会对使被删除的元素的迭代器失效。但是注意,失效后的迭代器你对它进行任何操作都将会导致 RE,因此你不能这样删除元素:

    for(set<int>::iterator it=st.begin();it!=st.end();it++){
        if((*it)>100) st.erase(it);
    }
    

    原因是你对失效的迭代器进行自增操作。
    而这样写就不会出现问题:

    for(set<int>::iterator it=st.begin();it!=st.end();it++){
        if((*it)>100) st.erase(it++);
    }
    

    值得注意的一点是,在 std::set 类型中,erase 函数是没有返回值的,因此也就不能通过调用 erase 函数获得下一个有效地址的位置,否则会获得 CE 的好成绩(London Fog

    3. 链表型容器

    对于链表型容器而言,虽然从外表上看起来它使用了数组型的结构,但实际上它内存的分布也是不连续的,因此删除一个元素并不会对其他元素的地址产生影响,因此可以通过 erase 函数的返回值获得下一个有效地址,也可通过在删除的同时自增迭代器的方式避免迭代器失效

  • 相关阅读:
    ubuntu 制做samba
    《Programming WPF》翻译 第4章 前言
    《Programming WPF》翻译 第4章 3.绑定到数据列表
    《Programming WPF》翻译 第4章 4.数据源
    《Programming WPF》翻译 第5章 6.触发器
    《Programming WPF》翻译 第4章 2.数据绑定
    《Programming WPF》翻译 第4章 1.不使用数据绑定
    《Programming WPF》翻译 第5章 7.控件模板
    《Programming WPF》翻译 第5章 8.我们进行到哪里了?
    《Programming WPF》翻译 第5章 5.数据模板和样式
  • 原文地址:https://www.cnblogs.com/ET2006/p/iterator-invalidate.html
Copyright © 2011-2022 走看看