1. list
- list 在 G2.9 中用的分配器是 alloc
- list 中的 data 是 node,类型是 link_type,link_type 是 list_node* ,是一个指针指向 list_node,指针的大小为 4 个字节(32位)
- __list_node 中有三个变量,分别是 data,prev,next,prev,next是指针,类型是 void_pointer ,即 void,用 void* 后还要转型,在后续的 G4.9 中有优化
- list 去申请内存,要有三部分,两个指针,一个 data
- 因为 list 是非连续空间,所以 iterator 不能是指针,由于链表是非连续的 iterator++,不能偏移到下一个 node
- 所有的容器要用 iterator,都要有一个typedef,iterator 代表某一个 class
- list_itertor 是一个 smart_pointer,是一个 class
- list的底层是双向环状链表,是前闭后开区间,有一个虚拟的节点,表现在图中就是灰色的那部分,也是 end() 所指向的部分,因为要实现前闭后开,所以就要构建出一个不属于本容器的节点,这样end(),才是最后一个节点的下一个节点
2. list_iterator
- iterator 中会有大量的操作符重载,因为要模拟指针,比如 *(解引用)、->、++
-
- 所有容器的 iterator 都至少有以上五个typedef
3. ++操作符重载
- operator++() 是前加加,operator++(int) 是后加加
- operator++() 的实现是 取 node 的 next ,将其赋值给自己本身,实现向后偏移到下一个节点
- 同理,operator--() 是取出 node 的 prev 指针,赋值给本身
- operator++(int) 的实现中
- 第一段代码,self tmp = *this
- *this 的 * 并不是调用的 operator*() 而是 调用拷贝构造函数,因为 *this 已经被解释为拷贝构造的参数
- 第二段代码,++*this
- 不会调用 operator*(),因为 *this 已经作为 operator++() 的参数
- 在 C++ 中,由于整数不能做两次连续的后加加,但是可以连续的两次前加加,所以iterator在设计前加加的时候,返回的就是引用,而后加加返回的则不是引用,这样做是为了模拟整数的++运算符
4. *与-> 操作符重载
- operator*() 返回的是 node 的 data,这个data可以是一个对象
- operator->() 返回的是 (*node).data 的地址,假设 node 的 data 是一个对象,那么取出来以后对这个对象取地址,就可以使用 -> 操作符,对其进行操作,可以看成是对象的一个指针,这样就可以修改其中的 public 的值,或者调用其中的 public 的函数
-
- 根据上图,iterator 不是一个指针,所以利用->操作符,会先调用它的 operator()->重载函数,直到取到一个地址,也就是一个指针,指向要操作的数,这是才可以进行成员的存取
5. G4.9 改进
- 原本传入 list_iterator 的参数要三个,分别是 T,T&,T*,现在只需要传入一个了
- 只需传入一个以后,typedef 也进行了修改,改成了 typedef _Tp* pointer,typedef _Tp& reference,在typedef定义的时候才加上操作符,变成指针或者引用
- 指针部分也改了,现在 list node分成了两部分,一部分是_list_node,继承了 _list_node_base,其中_list_node_base 中含有前后两个指针,他们的类型也从原来的 void* 改为了 结构体本身的指针类型
6. G4.9 变化
- 在4.9中,list 变为 8 个字节
- list本身没有大小,所以大小为0,要看他的父类
- 父类中有一个data
- 父类内含的 List_impl 内含 List_node_base,其中有两个指针,一个是 m_next,另一个是m_prev
- 所以两个指针是 8 个字节
- 和之前一样,list 的 node 指的就是空白节点,所以取 begin() 的时候,取的就是 node 的 next,而取end(),就是取空白节点