前言:
观看C++的list前需要对链表有一些了解,如C语言的链表结构。本片仅介绍list容器中常用的接口函数概念以及使用。
list的概念:
简而言之,C++的list是一个双向带哨兵位的链表容器模板
list的构造:
1.list():默认构造
2.list (const list& x) :拷贝构造函数
3.list (InputIterator first, InputIterator last) 用[first, last)左闭右开的区间中的元素构造list.
上图的输出打印是使用范围for进行打印,而范围for底层为list的迭代器。list的迭代器与vector、string的迭代器都不相同,这点小编会再下面进行大概讲解。
list迭代器(iterator)的使用:
1.iterator begin();
list的begin返回的是第一个有效节点的地址。
2.iterator end();
list的end返回的是哨兵为节点的地址。
那么从上面的begin与end可以看出,使用迭代器遍历list,仅仅只需要解引用迭代器以及++迭代器就能取得我们想要的值与让迭代器走向下一个节点,那么有没有想过一个问题,list的迭代器与vector这种类似数组的迭代器底层是否是一样的呢?
vector是一个天然的数组,而数组是一段连续的地址空间,vector的迭代器可以直接进行++就可以找到下一个数据的地址,解引用也可以直接访问数据
而从上图的list是一个不连续的空间,单直接进行++的话会访问到当前节点+1的地址空间,那么此时就变成了野指针。并且对list迭代器进行*(解引用)操作如果单纯的来看,对it解引用会是一个节点,而并非节点内的数据。但根据输出可以看到list的迭代器与vector的迭代器使用起来并无差别
但其实这是对list迭代器进行了封装操作,使得上层的使用看起来是一样的,但其实底层已经完全不一样了但为了方便理解list可暂时将迭代器理解成一个指针。
list capacity(容量)接口
1.list.empty():判断当前链表是否为空
empty函数是判断除哨兵位节点外是否还有其他节点,如果有则不为空,如果没有则为空.
2.list.size():返回当前链表的节点个数
list的modifiers(修饰符)接口函数
1.list.push_back
2.list.insert:
从上图可以看到,如果直接还是和之前vector一样向在第二个位置插入一个值,那么首先要让迭代器走到第二个位置,那么在list中是不能直接进行+2的操作,必须通过循环迭代到第二个位置。
那么在insert里存不存在迭代器失效问题呢?
答案是显而易见的,迭代器肯定是不会失效的,因为list不会涉及到扩容问题,同时此时pos也没有改变指向的位置,所以迭代器不会有失效的问题
3.list.erase
那么list的erase是否会有迭代器失效的问题?
我们可以看到,当erase后如果在对it迭代器进行操作,vs则会进行强制检查(根据编译环境不同,处理环境也不相同),则不允许再继续使用,如果想继续使用的话,C++同样也给出了方案,可以看到erase会返回一个迭代器,而返回的迭代器就是下一个链表的位置。所以需要 it迭代器重新赋值就可以继续使用。