文章里用到查询C++的网址为:cplusplus.com - The C++ Resources Network
源代码是stl30.tar.gz
目录
前言
我们list的实现依旧先从源代码入手,我们需要搞清楚部分的逻辑,这样方便我们去模拟实现。
link_type是节点的指针。接着我们去观察一下无参的初始化。
这里弄得是哨兵位的节点。get_node是在内存池申请内存,类似malloc申请空间不初始化。
接着我们来浅浅的观察一下push_back。某个位置前面插入。
所以其实我们明白链表的结构,很多都能够大概猜测出来。
一、成员变量
首先链表我们需要定义一个节点,只是我们这里需要用模板来实现。
还需要完成构造函数。
接着就完成成员变量的创建。(typedef只是为了写代码简单一点)

二、构造函数
我们先完成无参的构造函数,源代码中是用内存池,但我们这里简单实现一下,new也是动态开辟的空间。

这里我们再实现简单的size()和empty()。

三、push_back()
push_back逻辑上也很简单,因为是双向循环链表,我们需要先创建一个新节点,然后把新节点的尾指针指向哨兵位,旧的尾节点的下一个指针指向新的节点,新节点的头指针也要指向旧节点,哨兵位的头指针指向新节点。
四、迭代器
(1)普通迭代器
迭代器我们就不能单纯使用原生指针来,因为list两个节点之间物理上没有联系,我们加加也不会到下一个节点去。所以我们先观察一下源代码里面是怎么实现的。
重载了解引用返回节点数据。

也重载了++。
我们链表做不到vector和string结构的连续,但是我们list有着下一个节点的地址,所以我们可以用类型对节点指针进行封装来实现。我们就可以定义struct迭代器,struct默认公有,class则默认是私有。
这样我们完成了对自己list迭代器的封装,我们就可以去实现迭代器的begin()等等。
(2)const迭代器
我们要分清楚const iterator是迭代器本身不能修改,而我们要模拟实现的是const_iterator是指向内容不能修改。
但我们这样复制过来一个类,有点复杂了,我们先来看看库里面是怎么实现的呢?
但在编译后其实本质是相同的,一个是我们自己实现的,一个是通过类模板让编译器实例化出两个不同的类。
(3)迭代器失效
我们能够发现在list中,我们跟之前vector相似的代码,却不会发生迭代器失效。因为vector会挪动数据,而list位置不是连续的,在这种情况不会失效。

那在什么情况会发生迭代器失效呢?在删除一个节点,如果不重置的话,就相当于访问野指针了。
五、insert
insert是在pos位置插入数据。所以要拿到当前位置和前一个位置的节点,然后去更改两个位置的指向关系,将新的节点指向关系理清楚就很容易模拟实现出insert了。

完成了insert其实我们可以不用自己再实现push_back()和push_front()的,只需要对insert进行复用。

六、erase,pop_back,pop_front
删除pos位置也很简单,就是找到前一个位置和后一个位置,然后将它们链接起来就可以了。注意要返回删除位置下一个的。
这样我们依旧可以复用erase来实现头删和尾删。

七、operator->


为什么operator->是这样实现呢,为什么返回T*呢,其实这里为了可读性省略了一个->,我们可以详细写出来,这样会比较清晰。
八、析构函数,拷贝构造函数,赋值重载,clear,swap
析构函数我们进行对clear的复用就可以了。

拷贝构造函数我们需要注意我们不能单纯的循环尾插,因为链表并没有构造出哨兵位的头节点,所以我们刚好可以实现一个空链表的初始化来复用。
接着我们来验证一下拷贝构造。
对于赋值重载我们依旧使用现代写法也就是复用库里面的swap。