迭代器 | 一行朱砂 到底圈了谁
Cobb 643 0

知识储备

博主分析的十分详细 结论:在STL里,我们不能以指针来看待迭代器,指针是与内存绑定的,而迭代器是与容器里的元素绑定的,删除了之后,该迭代器就失效了,在对其重新赋值之前,不能再访问此迭代器。

一、什么是迭代器(面向对象的指针) ? 迭代器就是用oop表示的指针,每个容器针对迭代器都提供了自己的相应运算符的重载函数, 使用迭代器遍历所有容器的代码都是一样的, 其遍历的差异都被封装在了迭代器相应的运算符重载函数里面

问题:你知道迭代器失效问题吗? 什么场景下会出现? 场景:通过迭代器在容器中进行增加或删除元素,迭代器会出现失效问题 例如:vector中元素需要扩容的时候,原来的内存都没了,迭代器就失效了。。

解决办法:用insert或者erase方法,会返回插入完成或者删除完成后,该位置 新的迭代器,更新一下迭代器变量就可以

三个示例

示例一


#include <iostream>
#include <vector>    // std::vector<int>
#include <list>
#include <string>
#include <algorithm>
#include <stack>   // stack
#include <queue>   // queue   优先级队列priority_queue
#include <stdlib.h>
#include <time.h>
#include <functional>  // 函数对象
#include <unordered_map>
#include <set>
#include <typeinfo>    // 查看C++变量的类型
using namespace std; // using 指示符   using std::vector;



int main()
{
    int arr[] = { 12,5,67,8,90,8 };
    int size = sizeof arr / sizeof arr[0];

    list<int> ilist(arr, arr+size);

    //ilist.remove(8);
    for (auto it = ilist.begin(); it != ilist.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    // 找到8,并把它删除
    // 在用迭代器变量容器的过程中,容器的元素个数是不能改变的
    // 如果在遍历过程中增加了元素或者删除了元素,原来的迭代器
    // 就全部失效了
    for (auto it = ilist.begin(); it != ilist.end();)
    {
        if (*it == 8)
        {
            // ilist.remove(8);
            // 如果要连续删除,此处必须用erase的返回值更新it
            // 防止迭代器失效
            it = ilist.erase(it);
        }
        else
        {
            ++it;
        }
    }

    for (auto v : ilist)
    {
        cout << v << " ";
    }

    // 遍历ilist,在每一个偶数前面插入比偶数小1的数字
    // 12 5 67 90     =>   11 12 5 67 89 90   
    // insert(it, val)
    for (auto it = ilist.begin(); it != ilist.end(); ++it)
    {
        if (*it % 2 == 0)
        {
            it = ilist.insert(it, *it - 1);
            ++it;
        }
    }

    for (auto v : ilist)
    {
        cout << v << " ";
    }

    cout << endl;
}


示例二


int main()
{
    list<int> l;
    l.push_back(20);
    l.push_back(30);
    l.push_back(40);
    l.push_front(12);
    l.push_front(34);
    l.push_front(67);

    // 34 12 20 30
    l.pop_back();
    l.pop_front();

    // C++11提供了更加简便的迭代器遍历容器的方式
    for (auto v : l)
    {
        cout << v << " ";
    }
    cout << endl;

    // C++11 提供了auto,自动推导类型
    // list<string>::iterator it = l.begin();
    // [begin, end)
    // it:迭代器  指针  位置
    // 通过迭代器*it,既可以读数据,也可以修改数据
    for (auto it = l.begin(); it != l.end(); ++it)
    {
        //*it += 1;
        cout << *it << " ";
    }
    cout << endl;

    list<string> slist;
    slist.push_back("china");
    slist.push_back("shanxi");
    slist.push_back("xian");

    for (auto it = slist.begin(); it != slist.end(); ++it)
    {
        cout << *it << " "; // operator*() *p    p->data
    }
    cout << endl;

    cout << "用简便的foreach遍历:";
    // 用迭代器遍历slist,把每一个元素赋给s
    for (auto &s : slist)   // 遍历slist类对象,用引用接收???????
    {
        cout << s << " ";
    }
    cout << endl;

    vector<string> v;
    v.push_back("ccc");
    v.push_back("bbbb");
    v.push_back("aaa");
    for (auto it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    sort(v.begin(), v.end());
    for (auto it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    cout << "---------------------------" << endl;
    for_each(v.begin(), v.end(), [](auto &v) {
        if (v.size() == 3)
        {
            cout << v << endl;
        }
        });
}


示例三 vector扩容方式


int main()
{
    vector<int> v;

    for (int i = 0; i < 10; i++)
    {
        cout << v.size() << endl;
        cout << v.capacity() << endl;

        v.push_back(i);
    }
}


结论: 2倍扩容啊
0  0
1  1
2  2
3  4
4  4
5  8
6  8
7  8
8  8
9  16


评论区

索引目录