C++STL初阶(10):list的简易实现(下)

在上一文中我们完成了链表的多数基本接口,本文主要围绕构造函数进行补充

1. 链表的拷贝

在前文中我们没有手动实现拷贝构造,所以使用的就是编译器自动生成的浅拷贝

先使用一下编译器自动生成的浅拷贝:

我们在打印li2之前给li1加入一个数据:

现在还是完全的浅拷贝,拷贝构造过程中相当于只是将一个_head拷贝给另一个。两个链表有相同的_head。

插入一个会影响另外一个。

并且目前我们还没有实现析构函数,否则析构一个还会让另一个也无法使用。


 1.1 clear

传统方法是一个一个释放节点。在实现析构之前我们来实现一个clear

每一个容器都有clear,也就是保留大的框架,但是删除里面的数据。

类比到链表中,就是删除数据节点,留下头结点。

请问这样写正确吗:

                            

不对,it已经失效了。

复习:

在vector中,insert和erase都会让迭代器失效;

在list中,insert不会出现迭代器失效并且会返回插入的第一个节点,但是erase还是会迭代器失效的,返回的是被删除元素的下一个元素。

再次修改: 

                      

不对,it已经失效了,再++就加多了

正确写法:

void clear() {
	//iterator it(_head->_next);
	iterator it = begin();
	while (it != end()) {
		it = erase(it);
	}

 1.2 析构 

析构直接复用clear

                           

析构和clear的区别就是前者会将大结构也清理干净。


 1.3 拷贝构造(拷贝构造必须传引用)

综上所述,我们需要自己实现拷贝构造:

在创建一个全新的链表之后,一个一个的将被拷贝链表的内容全部push_back进去

                           

但是给_head赋值这一段其实就是默认构造,我们希望在一开始就调用这个默认构造中的内容。

直接调用默认构造显然是不可以的,我们将里面的内容独立出来。

                                   

为什么要将empty_init单独提取出来?

因为拷贝构造在一开始需要使用默认构造中“建立头结点”的功能。

                               

一般的范围for中,for后面都是(auto e: li)

为了应对T是较大的自定义类型的情况,我们将范围for中也传引用。

                  


2. 赋值运算符的重载

               

因为我们已经实现好了拷贝构造,所以直接传值传参。


3.initializer_list

在initializer_list参与下实现的花括号构造:

实现和拷贝构造非常相似。

因为initializer_list的逻辑就是从initializer_list一个一个拷贝出来。

                         ​​​​​​​

1、initializer_list不需要传引用传参,其本质就是两个指针,可以直接拷贝,代价不大

2、谨慎使用for循环,建议将auto都写成const auto&


小结

链表部分最重要的就是iterator

VS下的vector和string也没有用原生指针,而是封装过的,里面可能包含有标志等变量(比如erase之后不管是否真的失效都通过标志来表现该迭代器已经失效),但是只要观察早期版本,vector和string就是原生指针或者用原生指针换了个名字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值