• 迭代器C11


    迭代器

    迭代器失效

    容器使用迭代器时,不要改变容器的大小

    /在操作迭代器的过程中(使用了迭代器这种循环体),千万不要改变vectori容器的容量,也就是不要增加或者删除vectori容器中的元素
    /往容器中增加或者从容器中删除元素,这些操作可能会使指向容器元素的指针、引用、迭代器失效。
    失效就表示不能再代表任何容器中的元素。一旦使用失效的东西,就等于犯了严重的程序错误,很多情况下,程序会直接崩溃。

    原迭代器指的是进行操作之前保存的迭代器,包括begin()、end()以及其他位置的迭代器。

    vector:

    成员函数push_back():会在容器末尾添加一个元素。如果容器有剩余空间(capacity() > size()),则直接添加新元素到容器尾部。此时,原迭代器中end()会失效,其他的都不会失效。否则,会导致容器重新分配内存,然后将数据从原内存复制到新内存,再在尾部添加新元素。此时,由于内存重新分配,原迭代器(所有)都失效。

    成员函数pop_back():直接将容器中的最后一个元素删除,原迭代器中end()会失效,其余的都不会失效。

    成员函数insert(iterator, n):如果容器有剩余空间,先在容器尾部插入一个元素,然后将插入点及之后的元素都向后移动一位,然后在插入点创建新元素。否则,会导致容器重新分配内存,接着将插入点之前的元素复制过去,在插入点创建新元素,再将插入点之后的元素复制过去。因此,如果没有内存的重新分配,原迭代器中插入点及插入点之后的迭代器(包括end())都失效。如果有内存的重新分配,原迭代器(所有)都失效。

    成员函数erase(iterator):将删除点及之后的元素都向前移动一位,然后删除最后一个元素。因此,原迭代器中删除点之前的迭代器都有效,插入点及插入点之后的迭代器都失效。

    deque:

    成员函数push_back():会直接在容器末尾添加一个元素。原迭代器中end()会失效,其他的都不会失效。

    成员函数push_front():会直接在容器头部添加一个元素。原迭代器中begin()会失效,其他的都不会失效。

    成员函数pop_back():会直接删除最后一个元素。原迭代器中end()会失效,其他的都不会失效

    成员函数pop_front():会直接在容器头部删除一个元素。原迭代器中begin()会失效,其他的都不会失效。

    成员函数insert(iterator, n):如果插入点之前的元素较少,会在容器头部插入一个元素,然后将插入点及其之前的所有元素向前移动一位,再在插入点创建新元素。否则,将插入点及其之后的元素向后移动一位,再在插入点创建新元素。因此,向前移动则导致原迭代器中插入点及插入点之前的迭代器都失效;向后移动则导致迭代器中插入点及插入点之后的迭代器都失效。

    成员函数erase(iterator):如果删除点之前的元素较少,将删除点之前的所有元素向后移动一位,再删除第一个元素。否则,将删除点之后的所有元素向前移动一位,再删除最后一个元素。因此,向前移动将导致原迭代器中删除点及删除点之后的迭代器失效;向后移动将导致原迭代器中删除点及删除点之前的迭代器都失效。

    list:

    因为list的底层结构是双向链表,所有操作都只是针对节点移动指针,不会涉及到位置变化,操作影响的范围很小。

    成员函数push_back():原迭代器中end()会失效,其他的都不会失效。

    成员函数push_front():原迭代器中begin()会失效,其他的都不会失效。

    成员函数pop_back():原迭代器中end()会失效,其他的都不会失效

    成员函数pop_front():原迭代器中begin()会失效,其他的都不会失效。

    成员函数insert(iterator, n):原迭代器中插入点会失效,其他的都不会失效。

    成员函数erase(iterator):原迭代器中删除点会失效,其他的都不会失效。

    set、multiset、map、multimap

    关联容器的底层结构为红黑树,所有操作同list一样,都只是移动指针,各成员函数导致的迭代器失效问题同list。

    防止迭代器失效

      vector<int> v1;
    		v1.push_back(1);
    		v1.push_back(2);
    		v1.push_back(3);
    		v1.push_back(4);
    		v1.push_back(5);
    		vector<int>::iterator it = find(v1.begin(), v1.end(), 2);
    		if (it != v1.end())
    		{
    			it=v1.insert(it, 20);//及时更新了it指向的位置
    		}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    序列性容器::(vector和list和deque)
    erase迭代器不仅使所指向被删元素的迭代器失效,而且使被删元素之后的所有迭代器失效,所以不能使用erase(iter++)的方式,但是erase的返回值为下一个有效的迭代器。

        所以正确方法为::
        for( iter = c.begin(); iter != c.end(); )
              iter = c.erase(iter);
    
    • 1
    • 2
    • 3

    关联性容器::(map和set比较常用)
    erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器,
    所以正确方法为::

    for( iter = c.begin(); iter != c.end(); )
    c.erase(iter++);
    
    • 1
    • 2

    Tips:
    其实对于list两种方式都可以正常工作

    vector容器释放堆内存

    如果要在Vector容器中存放结构体类型的变量,经常见到两种存放方式.

    方式一:放入这个结构体类型变量的副本。

    方式二:放入指向这个结构体类型变量的指针。

    假设结构体类型变量是这样的,

    typedef struct student{
       char school_name[100];
       char gender;
       int age;
       bool is_absent;
    } StudentInfo;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么,方式一和方式二的实现分别如下所示:

    /*[方式一] 结构体放栈中,vector中放副本---------------------*/
    #include 
    #include 
    #include 
    typedef struct student{
       char school_name[100];
       char gender;
       int age;
       bool is_absent;
    } StudentInfo;
    
    typedefstd::vector<StudentInfo> StudentInfoVec;
    
    void print(StudentInfoVec* stduentinfovec){
       for (int j=0;j<(*stduentinfovec).size();j++)
        {
           std::cout<<
               (*stduentinfovec)[j].school_name<<"\t"<<
               (*stduentinfovec)[j].gender<<"\t"<<
               (*stduentinfovec)[j].age<<"\t"<<
               (*stduentinfovec)[j].is_absent<<"\t"<<std::endl;
        }
       return;
    }
    
    int main(){
       StudentInfo micheal={"Micheal",'m',18,false};
       StudentInfo cherry={"Cherry",'f',16,true};
       StudentInfoVec studentinfovec;
       studentinfovec.push_back(micheal);
       studentinfovec.push_back(cherry);
       print(&studentinfovec);
       return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    image-20221117232051188

    /*[方式二]  结构体放入堆中,vector中放指针---------------------*/
    typedef struct student{
       char* school_name;
       char gender;
       int age;
       bool is_absent;
    } StudentInfo;
     
    typedefstd::vector<StudentInfo*> StudentInfoPtrVec;
     
    void print(StudentInfoPtrVec*stduentinfoptrvec){
       for (int j=0;j<(*stduentinfoptrvec).size();j++)
        {
           std::cout<<
               (*stduentinfoptrvec)[j]->school_name<<"\t"<<
               (*stduentinfoptrvec)[j]->gender<<"\t"<<
               (*stduentinfoptrvec)[j]->age<<"\t"<<
               (*stduentinfoptrvec)[j]->is_absent<<"\t"<<std::endl;
        }
       return;
    }
     
    int main(){
     
       StudentInfoPtrVec studentinfoptrvec;
     
       char* p_char_1=NULL;
       p_char_1=new char[100];
       strcpy(p_char_1,"Micheal");
       StudentInfo* p_student_1=new StudentInfo;
       p_student_1->school_name=p_char_1;
       p_student_1->gender='m';
       p_student_1->age=18;
       p_student_1->is_absent=false;
       studentinfoptrvec.push_back(p_student_1);
     
       char* p_char_2=NULL;
       p_char_2=new char[100];
       strcpy(p_char_2,"Cherry");
       StudentInfo* p_student_2=new StudentInfo;
        p_student_2->school_name=p_char_2;
       p_student_2->gender='f';
       p_student_2->age=16;
       p_student_2->is_absent=false;
       studentinfoptrvec.push_back(p_student_2);
          
       print(&studentinfoptrvec);
       delete p_char_1;
       delete p_student_1;
       delete p_char_2;
       delete p_student_2;
       return 0;
        
        /*也可以这样释放内存*/
     
        //我们要释放内存,自己new的就要自己释放,否则会造成内存泄漏;
    std:vector<StudentInfoPtrVec *>iterator pos:
    for(pos =studentinfoptrvec.begin(:pos !=studentinfoptrvec.end();++pos)
    delete(*pos);
    }
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    p_student_2;
    return 0;

    /*也可以这样释放内存*/
    
    //我们要释放内存,自己new的就要自己释放,否则会造成内存泄漏;
    
    • 1
    • 2
    • 3

    std:vectoriterator pos:
    for(pos =studentinfoptrvec.begin(:pos !=studentinfoptrvec.end();++pos)
    delete(*pos);
    }

    
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0GfGth7-1668872304536)(https://raw.githubusercontent.com/Ding-yixia/Typora/master/image-20221117232144015.png)]
    
    • 1
    • 2
  • 相关阅读:
    Mysql ProxySQL的学习
    java中的异常,以及出现异常后的处理【try,catch,finally】
    H2数据库端口占用
    HTML+CSS网页设计期末课程大作业:【中国传统文化——古诗词】学生网页设计作品 dreamweaver作业静态HTML网页设计
    大前端工程化之写一个简单的webpack插件
    【华为OD统一考试B卷 | 100分】单词接龙(C++ Java JavaScript Python)
    js加密双重保障之sm2国密
    猿创征文|【设备云】FlexManager和阿里云MQTT通讯实例详解
    [附源码]计算机毕业设计绿色生鲜Springboot程序
    一文剖析 PolarDB HTAP 的列存数据压缩
  • 原文地址:https://blog.csdn.net/qq_55125921/article/details/127944073