news 2026/8/26 23:31:39

C++ list容器模拟实现:迭代器、构造与STL风格编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ list容器模拟实现:迭代器、构造与STL风格编程

list的模拟实现

1.1 list基本结构

list的结构是个带头双向循环链表,每个数据是存储在一个单独的节点内,这个节点除了存储数据还有两个指针分别指向前一个和后一个节点

这里定义节点的类用struct,定义list的类用class的原因是一个默认的共识,一个类如果它的所有成员都不期望用访问限定符限制的时候,习惯上就用struct定义,这里的list_node通常作为链表的一个子结构,是存储每个数据的一个最小单元,链表内是要大量访问内部数据的,所以这里不用访问限定符限制。虽然这样写后别人就可以随便访问这些结构了,但是有迭代器之后,在外层的角度是看不到节点的(例如从使用的角度,在接口使用的时候是不用链表的节点的,无论是访问修改还是插入删除,都是直接用迭代器的),即虽然list_node是公有的,但是其是一种隐形的封装,平时看不到也不会/不需要访问

这里 list_node< T >* _prev; 这个写法是C++ 模板语法 + 指针语法的组合

  1. list_node< T >是语法规定: list_node是定义的模板结构体,C++ 语法要求:使用模板类 / 结构体时,必须通过<模板参数>指定具体的泛型类型(这里T是模板参数),所以list_node< T >是模板结构体的 “实例化类型写法”,属于语法强制要求。
  2. *是语法规定:*是 C++ 中 “指针类型” 的声明符号,list_node< T >*表示 “指向list_node< T >类型对象的指针”,这是指针的标准语法。

补充一下这里模板声明的作用范围

模板声明的作用范围template< class T > 是 “模板参数声明”,它的作用域仅限于紧跟在它后面的那个类(或结构体、函数)。例如:

代码语言:javascript

AI代码解释

// 第一个类模板:list_node template<class T> // 作用范围:下面的 struct list_node struct list_node { ... }; // 第二个类模板:list template<class T> // 作用范围:下面的 class list class list { ... };

这里的两个 template< class T > 是独立的,分别服务于 list_node 和 list 两个类,彼此不影响。

新类模板需要重新声明每个类模板都是独立的实体,即使两个类的功能相关(比如链表的节点和链表本身),定义新的类模板时也必须重新写template< class T >。

原因是:模板参数 T 是 “当前类模板的局部参数”,只在当前类的范围内有效。比如 list_node 中的 T 和 list 中的 T 虽然名字相同,但实际上是两个独立的模板参数(只是习惯上用相同的字母表示)。

特殊情况:嵌套类模板如果一个类模板内部嵌套了另一个类,嵌套类可以直接使用外部类的模板参数,无需重复声明:

代码语言:javascript

AI代码解释

template<class T> class outer { // 嵌套类,直接使用外部的 T class inner { T data; // 这里的 T 继承自 outer 的 template<class T> }; };

但如果嵌套类需要自己的独立模板参数(比如同时支持 T 和 U),则需要单独声明:

代码语言:javascript

AI代码解释

template<class T> class outer { // 嵌套类有自己的模板参数 U template<class U> // 单独声明,作用范围:下面的 inner class inner { T a; // 来自 outer 的 T U b; // 来自 inner 自己的 U }; };
1.2 构造 + 尾插

在这里插入图片描述

尾插逻辑如图

在这里插入图片描述

在这里插入图片描述

这里运行不了,运行不了的原因是

list_node 缺少无参构造函数 在 List.h 中,list_node 结构体的构造函数只有带参数的版本(list_node(const T& x)),但没有无参构造函数。 而在 list 类的构造函数中,执行了 _head = new Node; —— 这里尝试调用 list_node 的无参构造函数,但该构造函数并不存在,因此会触发编译错误。

这里有三种解决办法:方法 1:利用list_node的带参构造显式传入默认值在 list 类的构造函数中,创建头结点时,显式调用 list_node 的带参构造,并传入 T 类型的默认值(通过 T() 触发 T 的默认构造,也就是使用匿名对象,T有可能是任意类型)。这样无需为 list_node 新增无参构造函数。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/26 23:29:24

AI赋能数字情感表达:Garden Letters如何重塑私密分享与创意创作

1. 从一封“数字花信”说起&#xff1a;为什么我们需要Garden Letters&#xff1f;最近几年&#xff0c;我身边不少朋友&#xff0c;包括我自己&#xff0c;都陷入了一种“数字表达困境”。逢年过节、生日纪念&#xff0c;想给对方发点特别的&#xff0c;但翻来覆去就是微信红包…

作者头像 李华
网站建设 2026/8/26 23:28:40

Jupyter Notebook 从安装到工程化:环境配置、内核管理与问题排查

如果你刚接触jupyter notebook&#xff0c;最典型的第一幕可能是这样&#xff1a;你装好 Anaconda&#xff0c;双击 Jupyter Notebook 图标&#xff0c;等待几秒后浏览器里弹出来一个目录列表&#xff1b;又或者你跟教程在终端里敲下jupyter notebook&#xff0c;结果系统直接提…

作者头像 李华
网站建设 2026/8/26 23:27:43

蒙特卡洛仿真建模:还原理发店真实排队系统的Matlab实战

1. 这不是一道“算术题”&#xff0c;而是一次对现实服务系统的真实压力测试 你有没有在理发店门口等过位&#xff1f;明明只剪个头发&#xff0c;却要盯着墙上那个跳动的叫号屏&#xff0c;看数字从23慢慢爬到18、15、12……最后终于轮到你&#xff0c;掏出手机一看——已经过…

作者头像 李华
网站建设 2026/8/26 23:25:46

ANOLISA v1.0:构建AI Agent与CLI深度融合的下一代智能命令行框架

1. 项目概述&#xff1a;当AI Agent开始“理解”你的命令行如果你是一个重度命令行用户&#xff0c;或者是一个开发者&#xff0c;那么下面这个场景你一定不陌生&#xff1a;你坐在终端前&#xff0c;面对一个复杂的系统问题&#xff0c;需要执行一系列命令来排查。你记得大概的…

作者头像 李华
网站建设 2026/8/26 23:20:24

Python构建轻量级电子考勤系统:从Flask后端到数据库设计全流程实战

1. 从零到一&#xff1a;为什么选择Python构建电子考勤系统&#xff1f; 最近在帮一个朋友的小型工作室解决考勤管理的麻烦事&#xff0c;他们之前一直用纸质签到&#xff0c;月底统计工时简直是场灾难。我评估了一下需求&#xff0c;发现市面上成熟的考勤系统要么功能臃肿、价…

作者头像 李华
网站建设 2026/8/26 23:20:18

APK封装系统实战:自动换包名与签名解决误报毒问题

简介&#xff1a;在移动应用开发与分发过程中&#xff0c;应用被安全软件误报为病毒是常见痛点&#xff0c;根源往往不在代码行为&#xff0c;而在于APK的静态身份信息——包名与签名指纹。杀毒引擎通过文件哈希、包名黑名单、签名证书指纹、代码特征码等维度进行静态扫描&…

作者头像 李华