一.push_back

void push_back(const T& x)
{
Node* newnode = new Node(x);
Node* tail = _head->_prev;
tail->_next = newnode;
newnode->_next = _head;
newnode->_prev = tail;
_head->_prev = newnode;
++_size;
}
对于类模板,在类外写类型时不想要写的那么麻烦,其实可以这么干:

二.迭代器的实现
1.普通迭代器
定义类时,struct默认成员变量以及函数是公有 ,而class 默认是私有。
链式存储每个节点间的地址并不连续,无法再像vector和string那样用原生指针代替迭代器。但可以通过单独声明一个iterator类**(用struct而非class,因为解引用要在外部能使用)**,以及在类里重载"*"以及"++","--","!=","==",以实现类似vector和string那样用原生指针代替迭代器。
重载"*"返回的是节点的_data:

重载"++":把下一个节点赋值给当前节点,以实现向后的效果,并返回节点的迭代器。

这么做就相当于迭代器指向下一个节点。
2.const_iterator
①.是const_iterator而不是const iterator

const修饰的对象是自身无法修改,而非所指向的内容无法修改。这里的const迭代器所要实现的,是使迭代器所指向的内容无法修改,而非迭代器本身无法修改,所以要单独实现一个迭代器,而非单纯在iterator前添加一个const那么简单。
②.具体实现
重新声明一个const_iterator类,并在某些接口后增加一个const。最后在list类模板里再重载一下
begin()和end()。
template<class T>
struct list_const_iterator
{
typedef node<T> Node;
typedef list_const_iterator<T> self;
Node* _node;
list_const_iterator(Node* node = T())
:_node(node)
{
}
const T& operator* ()
{
return _node->_data;
}
const T* operator->()
{
return &_node->_data;
}
self& operator++()//前置++
{
_node = _node->_next;
return *this;
}
self operator++(int)//后置++
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
self& operator--()//前置
{
_node = _node->_prev;
return *this;
}
self operator--(int)//后置
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!= (const self& s) const
{
return this->_node != s._node;
}
bool operator== (const self& s) const
{
return this->_node == s._node;
}
};
重载的begin和end:

三.重载->
为了使迭代器像对象的指针访问 对象的成员变量那样,需要重载一个"->"。
奇奇怪怪???
为啥重载的"->"返回的是一个地址呢?

重载其实是两个箭头
第一个 "->"是重载的运算符,返回指针。
第二个"->"是系统自带的,用于访问结构指针解引用并访问结构里的元素。
注:这里是向lta尾插了几个匿名对象 ,所以_data是个对象。因此有了_data的地址,就可以用 "->"访问这个对象里的元素。

四.迭代器失效
1.insert
list的insert并不会迭代器失效,原因在于insert以后it仍旧指向原空间。
2.erase
会失效,因为erase以后,it指向的空间会被释放,如果对it++,就相当于是对野指针++,那么it就是失效的。
五.析构函数

六.拷贝构造
以l2,l1为例,范围for会编译不通过,原因在于l2这个变量并未被初始化,没有哨兵位,或者哨兵位的指向并不满足初始化的形式(_head->_next = _head,_head->_prev = _head),这样的l2是无法使用push_back的。所以需要写一个empty_init接口来实现初始化。

自己遇到的问题
1.在typedef迭代器的时候忘记带T。迭代器是个类模板,而使用类模板需要传递模板参数!!


更改后:

2.node类模板里一定要带上构造函数。


构造函数(带缺省值):

其中缺省值传匿名对象,会去调用相应类型的默认构造函数,对于内置类型:int就给0,指针就给nullptr,以实现通用性。
积累经验:出现下面这种报错,就说明缺乏默认构造。

由于缺乏默认构造,系统会自动将语句识别为转换,所以实际的错误是没有默认构造。
3.打印接口不支持范围for


其实是打印接口中const的问题。范围for的底层是迭代器,由于形参con是const类型的,那么就应该替换const类型的迭代器。而我们实现的是普通类型的迭代器,所以这里的范围for是不支持的。需要去实现const迭代器。