记录STL容器中的数据成员和迭代器结构。(配合大佬源码分析食用)
1、list容器
先给出大佬的详细源码分析https://blog.csdn.net/qq_41453285/article/details/103571246
1.1 list数据成员
- 关于list容器的数据成员和迭代器如上图所示,因此可以得到list本身大小为4字节(
__list_node*
) - list的每个节点是一个结构体。以下是list的节点(node)结构:
template <class T>
struct __list_node {
typedef void* void_pointer;
void_pointer prev; //类型为void*。其实可设为__list_node<T>*
void_pointer next;
T data;
};
1.2 list容器迭代器
list迭代器是另外定义的结构体,不像vector容器的迭代器为原生指标,自增、自减和成员取用等操作需要自己定义。其示意图如下:
- 迭代器的数据成员就一个节点指针,代码如下:
template<class T, class Ref, class Ptr>
struct list_iterator {
typedef list_iterator<T, T&, T*> 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 size_t size_type;
typedef ptrdiff_t difference_type;
link_type node; / 迭代器内部当然要有一个原生指标,指向list的节点
};
2、vector容器
这里是大佬的源码分析https://blog.csdn.net/qq_41453285/article/details/103565158
- vector的数据成员和迭代器是:
template <class T, class Alloc = alloc>
class vector {
...
public:
typedef T value_type;
typedef value_type* iterator; //vector的迭代器是原生指标
protected:
iterator start; //表示目前使用空间的头
iterator finish; //表示目前使用空间的尾
iterator end_of_storage; //表示目前可用空间的尾
...
};
-
所以vector容器本身是12字节(三个value_type指针)
-
vector容器的示意图如下:
3、deque容器
贴上大佬的源码分析https://blog.csdn.net/qq_41453285/article/details/103614247
3.1 deque容器的数据成员
- 数据成员16字节(三个指针,一个unsigned int 4字节)
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque {
public: //Basic types
typedef T value_type;
typedef value_type* pointer;
typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
...
protected: //Internal typedefs
//元素的指针的指针(pointer of pointer of T)
typedef pointer* map_pointer;
protected: // Data members
iterator start;
iterator finish;
map_pointer map; //指向 map,map是块连续空间,其内的每个元素
//都是一个指标(称为节点),指向一块缓冲区
size_type map_size; //map内可容纳多少指针
...
3.2 deque容器的迭代器
deque是分段连续空间。维护其“整体连续”假象的任务,着落在迭代器的operator++ 和 operator-- 两个运算符身上。
deque的迭代器应该具有以下功能:
- 首先,它必须能够指出分段连续空间(亦即缓冲区)在哪里
- 其次它必须能够判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退时就必须跳跃至下一个或上一个缓冲区
- 为了能够正确跳跃,deque必须随时掌握管控中心(map)
- cur:当前迭代器所指的元素
- first:迭代器当前所指的缓冲区区间的头
- last:迭代器当前所指的缓冲区区间的尾
- node:指向deque管控器中的一个指针。用来指针当前迭代器所指的缓冲区归管控器中的哪一个指针所管理
stack和queue是对deque的功能做出相应限制的一个适配器。
4、红黑树
直接看大佬的分析吧(太强了)https://blog.csdn.net/qq_41453285/article/details/103645839
4.1 红黑树数据成员
- value是pair<key,data>
- KeyofValue是从value中“抽取”出key的函数体
- Compare是比较key值大小的函数体,用于排序
- RB-tree只有三个数据成员,size_type是4个字节,header是指针 4字节,Compare是函数体理论上0字节,但在实际中分配了1字节,所以总共9字节,但需要对齐成4的倍数,所以RB-tree是12字节
4.2 红黑树的迭代器
- RB-tree迭代器属于双向迭代器,但不具备随机定位能力,其提领操作和成员访问操作与list十分类似
- 注意:
RB-tree迭代器的前进操作operator++()调用的是基类中的increment()函数
RB-tree迭代器的后退操作operator–()调用的是基类中的decrement()函数 - 前进或后退的行为依据二叉搜索树的节点排列规则,再加上实现上的某些特殊技巧
set/multiset、map/multimap的底层实现是红黑树
5、hash table
膜拜大佬https://blog.csdn.net/qq_41453285/article/details/104260053
4.1 成员函数
- 下面就是哈希表的结构,其内部是以vector实现的
- 模板参数比较多,包括:
Value:节点的实值类型
Key:节点的键值类型
HashFcn:hash function的函数类型
ExtractKey:从节点取出键值的方法(函数或仿函数)
EqualKey:判断键值相同与否的方法(函数或仿函数)
Alloc:空间配置器。缺省使用std::alloc
4.2 迭代器
如上图,迭代器数据成员有:
_Node* _M_cur; //迭代器目前所指节点
_Hashtable* _M_ht;//保持对容器的连结关系(因为可能需要从bucket跳到bucket)
- 迭代器没有后退操作(operator–),也没有定义所谓的你想迭代器(reverse iterator)
- 迭代器前进操作(operator++):
其前进操作时首先尝试从目前所知的节点出发,前进一个位置(节点),由于节点被安置于list内,所以利用节点的next指针即可轻易达到进行的目的
如果目前节点正巧是list的尾端,就跳到下一个bucket内,跳过之后指向下一个list的头节点 - 下面是operator++的定义
template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&
_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next; //如果存在,就是它,否则进入if
if (!_M_cur) {
//根据元素值,定位出下一个bucket。其起头处就是我们的目的地
size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())//注意operator++
_M_cur = _M_ht->_M_buckets[__bucket];
}
return *this;
}
template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline _Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>
_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++(int)
{
iterator __tmp = *this;
++*this; //调用operator++()
return __tmp;
}
hash table是unordered_xxx的底层实现。