• C++ 迭代器失效问题


    今天同学华为面试被问到vector有什么问题了,我一拍脑门,vector有什么问题??

    原来是迭代器失效问题。先看看vector中:

    void test_vector_erase(){
        vector<int> v = {1,2,3,4,5};
        for(auto it = v.begin(); it != v.end(); it++){
            if(*it == 3)
                v.erase(it);
        }
        for(int& x : v) cout<<x<<" ";
    }

    我本来是想以这个例子举例的,但似乎没有bug??给我整不会了。

    但是我又分别测试了删除 1 和删除 5 的情况,答案是删除5的时候会出问题

    void test_vector_erase(){
        vector<int> v = {1,2,3,4,5};
        for(auto it = v.begin(); it != v.end(); it++){
            if(*it == 5)       //会出问题, 这里改成*it  > 2也会出问题
                v.erase(it);
        }
        for(int& x : v) cout<<x<<" ";
    }

    其实erase操作之后it还是会留在原位置,比如1,2,3,我们删除了2,变成了1,3,it由原来指向变成了指向3,这个时候做--操作,抵消for循环里面的++操作可以得到正确的结果

    void modify_vector_erase(){
        vector<int> v = {1,2,3,4,5};
        for(auto it = v.begin(); it != v.end(); it++){
            if(*it > 2) {
                it = v.erase(it);
                it--;
            }
        }
        for(auto it = v.begin(); it != v.end(); it++){
            cout<<*it<<" ";
        }
    }

    再来看看insert操作是如何让迭代器失效的

    int test_vector_insert(){
        vector<int> v(3);
        v.reserve(10);  //注意这句话, 不加这句话输出的结果是99 98 0 0 100 3 98 ,可以看出迭代器并不在我们想要的位置,因为insert当空间不够时会引起扩容,原数组被搬到了另一块更大的空间,迭代器还留在原来的位置
      //加上这句话,也就是vector的预分配函数后,我们insert四个数不会引起扩容,因此会打印出正确结果 3 2 1 0 100 99 98 
    v[0] = 100;v[1] = 99, v[2] = 98; auto it = v.begin(); v.insert(it, 1, 0); v.insert(it, 1, 1); v.insert(it, 1, 2); v.insert(it, 1, 3); for(auto it = v.begin(); it != v.end(); it++){ cout<<*it<<" "; } return 0; }

    再看看关联性容器map, 对于map和list,这种存放位置不连续的容器,当客户端对它进行元素新增操作(insert)或者删除(erase)操作时,操作之前的所有迭代器在操作完成后都依然有效,被删除的那个元素的迭代器是个例外。

     首先直接删除任意一个元素后就不会继续遍历后面的元素了,输出1,3,4,5。被删除的it被删除后还是指向3,而此时it的下一个是mp.end()

    void test_map_erase(){
        map<int, char> mp{{1,'a'},{2,'b'},{3,'c'},{4,'d'},{5,'e'}};
        for(auto it = mp.begin(); it != mp.end(); it++){
            if(it -> first > 2){
           mp.erase(it);
           cout<<it->first<<endl;
         }     }
    for(auto it = mp.begin(); it != mp.end(); it++) cout<<it->first<<" "; }

    下面这样可以完整删除3,4,5

    void test_map_erase(){
        map<int, char> mp{{1,'a'},{2,'b'},{3,'c'},{4,'d'},{5,'e'}};
        for(auto it = mp.begin(); it != mp.end(); it++){
            if(it -> first > 2) {
                mp.erase(it++);
                it--;
            }
        }
        for(auto it = mp.begin(); it != mp.end(); it++)
            cout<<it->first<<" ";
    }

    总之,我觉得不会有哪个傻蛋会一遍修改容器一边遍历容器吧!

    另外erase操作和remove操作也是有区别的

    //remove的官方解释,是把一个范围内的某个数删除,但是并没有释放容器空间
    template <class ForwardIterator, class T>
      ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
    {
      ForwardIterator result = first;
      while (first!=last) {
        if (!(*first == val)) {
          if (result!=first)
            *result = move(*first);
          ++result;
        }
        ++first;
      }
      return result;
    }
    
    //vector 中的 erase是删除某个位置并且释放了空间的(ps:map的源码我没看到,不知道有没有释放)
    iterator erase(iterator position){
        if(position + 1 != end())
            copy(position + 1, finish, position);
        --finish;    //finish是vector中已使用空间的尾,end_of_storage 是vector可使用空间的尾
        destroy(finish);
        return position;
    }

    STL共有这五种类型的迭代器,迭代器其实是一种行为类似智能指针的对象。

           

  • 相关阅读:
    计算机进制转换
    十进制二进制转换
    windows XP 下怎样查看系统运行时间总计?
    “编译器错误信息: CS0016: 未能写入输出文件”解决方法
    用ntsd关进程
    Hosts文件的位置
    开机显示client mac addr...... 错误的解决办法 .
    无法嵌入互操作类型“Microsoft.Office.Interop.Excel.ApplicationClass”。请改用适用的接口 .
    【转】XP远程桌面连接2008提示:远程计算机需要网络级别身份验证,而您的计算机不支持该验证 .
    关于Access的郁闷二三事。。。
  • 原文地址:https://www.cnblogs.com/Dancing-Fairy/p/15264970.html
Copyright © 2020-2023  润新知