zoukankan      html  css  js  c++  java
  • STL中erase的小心使用

    先看如下一道改错题:

    #include<iostream>   
    #include<vector>   
    using namespace std;   
    
    void print(vector<int>);   
    
    int main()   
    {
        vector<int>   array;   
        array.push_back(1);   
        array.push_back(6);   
        array.push_back(6);   
        array.push_back(3);   
        //删除array数组中所有的6   
        vector<int>::iterator itor;   
        vector<int>::iterator itor2;   
        itor=array.begin();   
    
        for(itor=array.begin();itor!=array.end(); )   
        {   
            if(6==*itor)     
            {   
                itor2=itor;
                array.erase(itor2);   
            }       
            itor++;
        }
        print(array);   
        return 0;
    }       
    void print(vector<int> v)   
    {
        cout<<"/n vector size is: "<<v.size()<<endl;   
        vector<int>::iterator p = v.begin();   
    }

    答案解析:行itor=array.erase(itor);这句话后,itor不会移动,而只是把删除的数后面的数都往前移一位,所以删除了第一个6后,指针指向第2个6,然后在来个itor++,指针就指向array.end()了,给你画个草图:

    image

    修改如下即可:

    for(itor=array.begin();   itor!=array.end();   )   
        {   
            if(6==*itor)     
            {   
                itor2=itor;   
                itor = array.erase(itor2);//消除后返回下一个迭代   
            }   
            else   
            {   
                itor++;   
            }       
        }

    这仅仅是针对vector而言,其他容器又是怎样的呢?

    erase()函数的功能是用来删除容器中的元素
    删除某个容器里的某个元素:c.erase(T);
    看似一个简单的动作,然而对不同类型的容器,内部却做了截然不同的事情,后面介绍。

    假设有这样一个题目,将某个容器中所有满足条件N == X的元素删除,按照常规的思路应该有类似这样的代码:

    // 假设Container和container分别表示一种容器和对应的一个对象
    Container<T>::iterator it;
    for (it = container.begin(); it != container.end(); ++it)
    {
        if (N == X)
            container.erase(it);
    }

    然而这样的代码对于任一种容器都是错误的尴尬

    容器按内存分配方式可以分为链表容器和数组容器。
    所谓的链表容器指的是一种表现方式,包括list、slist等这样基于节点的容器(动态分配内存块)和set、map、multiset、multimap等关联容器(平衡树实现),而数组容器指的是在一块连续的内存上保存元素的连续内存容器,比如vector、deque、string等。
    链表容器以list为例,当执行container.erase(it)时,确实第一个满足条件的元素删除了,但这时it指针已经被删除了,它也不指向任何元素了,所以也只能到此为止了,也就是说上面的代码对于链表容器来说只能正确删除第一个满足条件的元素,针对这个问题我们首先想到的就是在删除指针之前,给其做个备份。
    将这个临时变量直接建立在erase实现里,这样做更简洁,也显得专业些。

    list<int>::iterator it; 
    for (it = lt.begin(); it != lt.end(); ) 
    {
        if (*it % 2 == 0)
            lt.erase(it++); //这里是关键
        else
            ++it;
    }

    链表容器使用erase删除节点还有一个特点,就是会将下一个元素的地址返回,所以也可以这样实现:

    list<int>::iterator it; 
    for (it = lt.begin(); it != lt.end(); ) 
    {
        if (*it % 2 == 0)
            it = lt.erase(it);//自动返回下一个元素的地址,不用再主动前移指针
        else
            ++it;
    }

    数组容器以vector为例,当执行container.erase(it)时,和上面提到的一样,第一个满足条件的元素删除了,但这时数组容器不允许中间有“空隙”,所以会做个大动作,就是将被删元素后面所有的元素前移(参考STL源码),而数组容器记录的是下标,所以删除元素后,当前下标定位的元素也就顺理成章的变成了原有队列中的下一个元素,同样以删除偶数为例,代码如下:

    vector<int>::iterator it = v.begin();
    for (it = v.begin(); it != v.end(); ) 
    { 
        if (*it % 2 == 0)
            v.erase(it);//删除元素后,后面元素自动往前移,不用挪动指                  
        else
            ++it;
    }

    网上有说在VS2005里面上面的v.erase(it)写法是行的  VS2008及2010却运行会出现错误 会出现
    vector erase iterator outside range  最保险的做法是将v.erase(it)改成 it=v.erase(it)

  • 相关阅读:
    laravel在控制器中动态创建数据表
    laravel模型关联:
    laravel的firstOrCreate的作用:先查找表,如果有就输出数据,如果没有就插入数据
    创建一个自定义颜色IRgbColor
    tnt_esri.dat Arcgis8.1安装license
    arcgis desktop 10.1 license manager无法启动问题解决
    解决ArcGIS安装之后出现的Windows installer configures问题
    Arcgis 10.1安装
    Arcgis10安装说明
    ARCGIS9.3安装说明
  • 原文地址:https://www.cnblogs.com/VIPler/p/4379565.html
Copyright © 2011-2022 走看看