list的迭代器很麻烦,物理结构不连续。类型对节点指针封装,重载operator*就可以获取里面数据
指针是四个字节,我们用迭代器封装,封装完了还是四个字节,物理上都是地址,但是
行为不同。
可以加上后置加加。没写拷贝构造,编译器默认生成拷贝构造,内置类型,指针也可能是内置类型,这有个迭代器指针走浅拷贝会不会有问题,不会,不会,begin返回第二个位置迭代器,
我期望it也指向这个节点,我要的就是浅拷贝,并不是说我有指针就需要深拷贝,而是看我的指针指向的资源是不是属于你的。链表需要深拷贝,stringvector需要深拷贝,指针指向的资源是指向他的,迭代器指向资源不是属于他的,是属于链表的,不需要深拷贝,仅仅是为了访问遍历链表,不需要深拷贝,更不需要析构,不可能释放,没析构就不需要拷贝构造和赋值。
迭代器模拟的是指针的行为,所以他还需要operator->,结构的指针才需要箭头
cpp
struct AA
{
int _a1 = 1;
int _a2 = 1;
};
void test_list1()
{
list<AA> lta;
lta.push_back(AA());
lta.push_back(AA());
lta.push_back(AA());
lta.push_back(AA());
list<AA>::iterator ita = lta.begin();
while (ita != lta.end())
{
cout <<*ita<<" ";
++ita;
}
cout << endl;
}
编译不通过,解引用每个数据是data
cpp
Ref operator*()
{
return _node->_data;
}
data是T类型,AA,AA不支持流插入,可以给AA重载个流插入,不支持也可以
可以重载个operator->

T是AA,就是返回AA*,这里怎么看怎么奇怪,
第一个箭头完了就是AA*,就可以解引用了,这里严格来说是两个箭头,为了可读性编译器省略了一个箭头,
上节课printcontrainer不仅针对链表,还针对任意容器,所有容器都支持迭代器,就支持for

加入print之后发现范围for不支持,print外面的范围 for支持,里面的就不支持了为什么,
普通容器迭代器替换普通的迭代器,const容器调用const迭代器,我们没有实现const迭代器,跑不了
为什么const加个-形成单独类型,而为什么不直接加const修饰,const迭代器是自身不能修改还是指向的内容不能修改,
要第二个 const iterator就修饰迭代器本身不能修改,
如何保证const迭代器指向的内容不能修改,我们现在不是原生指针了,是有个类型进行封装,迭代器修改指向的内容通过operator* 和operator->进行修改,

这就不能修改了,但是普通迭代器还是要改,这里加const迭代器。
cpp
template<class T>
struct list_const_iterator
{
typedef list_node<T> Node;
typedef list_const_iterator<T> Self;
Node* _node;
list_const_iterator(Node* node)
:_node(node)
{}
const T& operator*()
{
return _node->_data;
}
const T* operator->()
{
return &_node->_data;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
Self& operator--(int)
{
Self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s._node;
}
};


这重载了begin 和end 版本,
如果有最匹配的就走最匹配的,这是两个不同类模版实现的,没有的时候可以将就一下,普通的 const都可以调用const的,如果有更匹配的就走最匹配的

返回const迭代器这里不匹配了,还得改
模版类模版这些都一样他们会走按需实例化,返回的const 不能修改,但是这里没报错,模版不能生成对应代码,按需实例化是指模版要把具体类型实例化,实例化后才生成具体代码,
这个函数模版在这没有调用,编译器基础错误可以检查,也会编译它,会走一层浅浅扫描,看一下大框架不会走细节一些错误,
这种就不会,把这个函数放出来,就报错。把这个+=注释就行了。
但是这里搞一个list------ieetarator 一个list_const_iterator,不好。这两个类相似度太高了,解决一下
看一下库:
用的同一个类模版,但是除了穿了个T还传另外两个参数,
普通迭代器返回T引用和T*,如果const就const引用 * ,也就是说他用同一个类模版,增加两个模版参数去控制。

这两种方式没有本质区别,上面是两个类,类模版是模版,给不同参数,就是不同类型,
cpp
template<class T, class Ref, class Ptr>
struct list_iterator
{
typedef list_node<T> Node;
typedef list_iterator<T, Ref, Ptr> Self;
Node* _node;
list_iterator(Node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
Self& operator--(int)
{
Self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s._node;
}
};
ref是T引用还是constT引用,不知道看你传,
模版基础上再加模版,实例化出不同对象。模版复用实例化。
看一下迭代器失效的问题,链表里面插入还有没有迭代器失效的问题,没有,

链表不需要挪动数据,对后面关系没改变,erase有没有迭代器失效问题 有
删除之后迭代器野指针,不能++,
,assert的错现在才报出来,按需实例化,之前没调用erase,没细致检查
,野指针迭代器失效,erase会返回下一个位置迭代器


换成库里的会报错,
这里list不能写死
我取的是container
这样编不过,我要取模版里的,没实例化的,分不清类型变量,类型加typename,auto也行

insert也有返回值,返回刚插入的元素
析构实现一下,遍历链表一个一个释放,还有个很简单的方法
先实现clear,迭代器外部可以用,内部也可以用


看一下拷贝构造

浅拷贝了但是没蹦,写一个深拷贝:
但是这个代码编不过。可以通过调试来查,pushback需要有哨兵卫的头结点,list2一上来没有哨兵卫头结点,并且形成闭环结构,所以初始化一下
cpp
void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
list()
{
empty_init();
}
list(initializer_list<T> il)
{
empty_init();
for (auto& e : il)
{
push_back(e);
}
}
拷贝构造就好了,
赋值不写默认生成的是浅拷贝,此处报错,为什么拷贝构造不报错。搜一搜
用现代写法

