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

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

1. 链表的拷贝

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

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

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

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

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

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


1.1 clear

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

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

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

请问这样写正确吗:

++不对,it已经失效了。++

复习:

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

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

再次修改:

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

正确写法:

cpp 复制代码
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就是原生指针或者用原生指针换了个名字。

相关推荐
喜欢喝果茶.7 分钟前
QOverload<参数列表>::of(&函数名)信号槽
开发语言·qt
亓才孓8 分钟前
[Class类的应用]反射的理解
开发语言·python
努力学编程呀(๑•ี_เ•ี๑)8 分钟前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
坚果派·白晓明10 分钟前
在鸿蒙设备上快速验证由lycium工具快速交叉编译的C/C++三方库
c语言·c++·harmonyos·鸿蒙·编程语言·openharmony·三方库
小镇敲码人17 分钟前
深入剖析华为CANN框架下的Ops-CV仓库:从入门到实战指南
c++·python·华为·cann
island131429 分钟前
CANN GE(图引擎)深度解析:计算图优化管线、内存静态规划与异构任务的 Stream 调度机制
开发语言·人工智能·深度学习·神经网络
坚持就完事了33 分钟前
Java中的集合
java·开发语言
魔芋红茶37 分钟前
Python 项目版本控制
开发语言·python
云小逸1 小时前
【nmap源码解析】Nmap OS识别核心模块深度解析:osscan2.cc源码剖析(1)
开发语言·网络·学习·nmap
冰暮流星1 小时前
javascript之二重循环练习
开发语言·javascript·数据库