list源码实现
G2.9版本的list源码
list底层实现为双向循环链表,并且环状链表的尾端还有一个空白节点,代表尾后迭代器指向的节点,用以符合STL前闭后开的原则,其示意图如下:
- list代表一个双向链表,__list_node代表链表中每一个节点,__list_iterator代表每一个节点的迭代器
- list中存在一个__list_node*类型的节点指针begin()和end()分别指向list的头部节点和尾部节点,另外尾部节点不赋值,头部节点赋值,以满足list前闭后开的特性
- __list_node中的指针类型未void*,之后在使用的时候需要进行转换
- list的初始化大小为4个字节,因为它只有一个__list_node*类型的node
G4.9版本的list源码
- list代表一个双向链表,list继承于_List_base,且_List_base包含_List_impl,_List_impl继承于_A,即利用内存管理保存_List_node(_List_node相当于一个节点,继承于_List_node_base,保存了前后指针和data),同时保存了变量_M_node
- list中存在一个_List_node_base*类型的节点指针begin()和end()分别指向list的头部节点和尾部节点,另外尾部节点不赋值,头部节点赋值,以满足list前闭后开的特性
- list的初始化大小为8个字节,因为它只有一个_List_node_base类型的变量_M_node,而该变量由两个指针构成
G4.9和G2.9源码比较
list中的iterator的设计
template <class T, class Ref, class Ptr>
struct __list_iterator{
typedef __list_iterator<T, Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef ptrdiff_t difference_type;
link_node node;
reference operator*() const { return (*node).data; }
pointer operator->() const { return &(operator*()); }
self& operator++()
{ node = (link_type)((*node).next); return *this; }
self operator++(int)
{ self tmp = *this; ++*this; return tmp; }
......
};
- 从 self tmp = *this; 这个语句来看有两种执行方案,
1. this可以先调用operator*(),再调用=,
2. 先将this指针转化为变量,再调用operator=(),
但是operator*()和operator=()的返回值不同,通过同时尝试两种不同的情况就会发现,方案2是可行的 - 另外需要考虑prefix和profix返回值的情况,由于连续两次后++不被允许,而连续两次前++被允许,所以prefix返回引用型,postfix返回普通变量型
详情请参考【C++の相关概念】operator->重载
注意事项
list为何不能使用::sort()进行排序
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last){
if(first != last){
__introsort_loop(first, last, value_type(first), __lg(last - first) * 2);
__final_insertion_sort(first, last);
}
}
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last,
T*,
Size depth_limit){
......
RandomAccessIterator cut = __unguarded_partition
(first, last, T(__median(*first, *(first + (last - first)/2), *(last - 1))));
......
}
通过阅读以上::sort()源码发现,:sort()支持的迭代器是随机访问迭代器,而list中的迭代器不是随机访问迭代器,所以也就不提供这个操作。这样设计是合理的,因为list是链表,无法在线性时间内得到递增或递减k次的结果。
list的迭代器类型以及相关操作的时间复杂度
双向迭代器
list为可反转容器
不支持随机访问元素
末尾插入删除元素 常量时间
中间或开头删插元素 常量时间
list的迭代器失效问题
增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效。