C++ STL 完整入门笔记[6]:list 底层源码手写剖析:双向链表与迭代器设计全解
前言std::list是 STL 中典型双向循环链表容器和 vector 连续数组底层完全不同vector 随机访问 O (1)、中间插入删除 O (n)list 不支持随机访问但任意位置插入、删除仅 O (1)。本文结合手写简易版 list 源码拆解底层结构、迭代器区分、核心接口insert/erase/push_back、const 迭代器底层设计难点把手写 list 的所有核心知识点一次性梳理清楚。一、list 底层存储结构带哨兵头结点的双向循环链表1. 节点结构体_list_nodelist 每一个存储数据的节点都包含三部分数据、前驱指针、后继指针templateclass T struct _list_node { T _data; _list_node* _next; _list_node* _prev; };2. list 类本体哨兵头结点_headlist 内部只维护一个哨兵头结点_head链表形成双向循环_head-_next指向链表第一个有效节点begin()_head-_prev指向链表最后一个有效节点end()返回迭代器指向哨兵头结点本身哨兵节点优势链表为空 / 非空时insert、erase逻辑完全统一无需单独处理空链表边界。templateclass T class list { public: typedef _list_nodeT Node; private: Node* _head; // 哨兵头结点 };二、list 迭代器深度拆解普通迭代器 vs const 迭代器list 迭代器不是原生指针是封装链表节点指针的类因为链表节点不连续不能直接it跳转下一个元素。1. 迭代器模板设计核心难点迭代器模板接收两个模板参数T存储数据类型Ref引用类型普通迭代器传Tconst 迭代器传const Ttemplateclass T, class Ref struct _list_iterator { typedef _list_nodeT Node; typedef _list_iteratorT, Ref Self; Node* _node; // 构造绑定链表节点指针 _list_iterator(Node* node) :_node(node) {} // 解引用 *it Ref operator*() { return _node-_data; } // 箭头访问 it-xxx T* operator-() { return _node-_data; } // 前置 Self operator() { _node _node-_next; return *this; } // 前置-- Self operator--() { _node _node-_prev; return *this; } // 迭代器比较 bool operator!(const Self other) const { return _node ! other._node; } };2. 两种迭代器 typedef 区分在 list 类内部通过上面迭代器模板实例化出两种迭代器templateclass T class list { public: typedef _list_iteratorT, T iterator; typedef _list_iteratorT, const T const_iterator; // ... private: Node* _head; };关键区别普通迭代器 iteratorRefT*it返回数据引用可修改链表节点数据listint lt; listint::iterator it lt.begin(); *it 100; // 合法可修改const 迭代器 const_iteratorRefconst T*it返回 const 引用禁止修改节点数据void print(const listint lt) { listint::const_iterator it lt.begin(); // *it 100; 报错const迭代器不能修改数据 cout *it; }3. begin () /end () 接口实现// 普通迭代器begin iterator begin() { return iterator(_head-_next); } // const迭代器beginconst对象调用 const_iterator begin() const { return const_iterator(_head-_next); } // end永远返回哨兵头结点 iterator end() { return iterator(_head); } const_iterator end() const { return const_iterator(_head); }三、核心接口源码实现与图解1. 构造函数、析构函数构造初始化哨兵循环链表list() { _head new Node; _head-_next _head; _head-_prev _head; }析构循环销毁所有节点释放哨兵~list() { iterator it begin(); while(it ! end()) { it erase(it); // erase自动返回下一个有效迭代器 } delete _head; _head nullptr; }2. insert 任意位置插入O (1)逻辑图解pos 迭代器指向当前节点 cur新建 newnode 插入 cur 前面保存 cur 前驱 prev cur-_prevprev 后继指向 newnodenewnode 前驱指向 prev后继指向 curcur 前驱指向 newnodevoid insert(iterator pos, const T val) { Node* cur pos._node; Node* newnode new Node; newnode-_data val; Node* prev cur-_prev; prev-_next newnode; newnode-_prev prev; newnode-_next cur; cur-_prev newnode; }3. erase 删除指定迭代器位置O (1)逻辑图解删除 pos 指向 cur 节点连接前后节点返回下一个有效迭代器保存 cur 前驱 prev、后继 nextprev 后继改为 nextnext 前驱改为 prev释放 cur 节点内存返回迭代器绑定 next 节点iterator erase(iterator pos) { Node* cur pos._node; Node* prev cur-_prev; Node* next cur-_next; prev-_next next; next-_prev prev; delete cur; return iterator(next); }4. push_back /push_front 复用 insert底层直接调用 insert简化代码// 尾插在end()哨兵前插入 void push_back(const T x) { insert(end(), x); } // 头插在begin()第一个元素前插入 void push_front(const T x) { insert(begin(), x); }四、手写 list 核心易错点总结迭代器不能复用原生指针vector 迭代器本质是T*原生指针list 节点不连续必须封装节点指针实现迭代器。const 迭代器不能修改数据迭代器模板通过第二个模板参数区分引用类型const 迭代器解引用返回 const 引用拦截数据修改。哨兵头结点统一边界逻辑无论链表空还是有数据insert、erase 无需额外判空空链表begin()end()。erase 迭代器失效问题erase 传入的 pos 迭代器失效但返回值是下一个有效迭代器vector erase 会导致后续所有迭代器失效list 仅被删除迭代器失效。list 不支持随机访问没有重载[]运算符不能lt[0]访问元素遍历只能依靠迭代器循环。五、list vs vector 底层对比特性std::list双向链表std::vector连续数组底层存储离散节点双向循环链表连续堆内存数组随机访问 []不支持O (n) 遍历支持O (1)头部 / 中间插入删除O (1)仅修改指针O (n)需要挪动元素迭代器失效仅被 erase 的迭代器失效erase 后所有后续迭代器失效内存开销每个节点存 prev/next 双指针开销大仅存储数据内存紧凑六、完整简易版 list 全部源码#includeiostream using namespace std; templateclass T struct _list_node { T _data; _list_node* _next; _list_node* _prev; }; templateclass T, class Ref struct _list_iterator { typedef _list_nodeT Node; typedef _list_iteratorT, Ref Self; Node* _node; _list_iterator(Node* node) :_node(node) {} Ref operator*() { return _node-_data; } T* operator-() { return _node-_data; } Self operator() { _node _node-_next; return *this; } Self operator--() { _node _node-_prev; return *this; } bool operator!(const Self other) const { return _node ! other._node; } }; templateclass T class list { public: typedef _list_nodeT Node; typedef _list_iteratorT, T iterator; typedef _list_iteratorT, const T const_iterator; list() { _head new Node; _head-_next _head; _head-_prev _head; } ~list() { iterator it begin(); while(it ! end()) { it erase(it); } delete _head; _head nullptr; } iterator begin() { return iterator(_head-_next); } const_iterator begin() const { return const_iterator(_head-_next); } iterator end() { return iterator(_head); } const_iterator end() const { return const_iterator(_head); } void insert(iterator pos, const T val) { Node* cur pos._node; Node* newnode new Node; newnode-_data val; Node* prev cur-_prev; prev-_next newnode; newnode-_prev prev; newnode-_next cur; cur-_prev newnode; } iterator erase(iterator pos) { Node* cur pos._node; Node* prev cur-_prev; Node* next cur-_next; prev-_next next; next-_prev prev; delete cur; return iterator(next); } void push_back(const T x) { insert(end(), x); } void push_front(const T x) { insert(begin(), x); } }; // 测试打印函数 void print(const listint lt) { listint::const_iterator it lt.begin(); while(it ! lt.end()) { cout *it ; it; } cout endl; } int main() { listint lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_front(0); print(lt); listint::iterator it lt.begin(); it; lt.erase(it); print(lt); return 0; }结语手写 list 是吃透 STL 容器底层的经典案例重点掌握双向循环链表哨兵设计、模板迭代器区分普通 /const、insert/erase 指针修改逻辑三大核心。 对比 vector 底层实现后可以根据业务场景灵活选择容器频繁中间插入删除选 list随机访问、尾部扩容选 vector。

相关新闻

ThreadLocal 原理与实践:线程隔离、内存泄漏与使用边界

ThreadLocal 原理与实践:线程隔离、内存泄漏与使用边界

ThreadLocal 原理与实践:线程隔离、内存泄漏与使用边界 目录 线程私有变量Thread 的内部结构ThreadLocalMapset、get 和 remove 的过程内存泄漏与数据污染实战场景使用边界小结 多线程操作共享变量时,通常需要考虑加锁、原子操作和可见性问题。但有些…

2026/7/29 1:28:53 阅读更多 →
基于Arduino与PS2手柄的Makeblock搬运遥控车制作全攻略

基于Arduino与PS2手柄的Makeblock搬运遥控车制作全攻略

1. 项目概述:当经典手柄遇上开源硬件如果你手头正好有一套Makeblock的金属结构件,几个电机,还有一个在角落里吃灰多年的SONY PS2手柄,那么恭喜你,一个充满乐趣的周末项目正在向你招手。这个项目的核心,就是…

2026/7/29 1:28:53 阅读更多 →
RAG文档切片优化:解决AI检索中的上下文断裂问题

RAG文档切片优化:解决AI检索中的上下文断裂问题

1. RAG检索中的文档切片困境:当AI变成"近视眼"那天凌晨3点,我被报警短信惊醒——客户的知识问答系统突然开始胡言乱语。查看日志发现,当用户询问"我司2023年推出的新产品有哪些核心优势"时,系统竟回答"根…

2026/7/29 1:28:53 阅读更多 →

最新新闻

计算机毕业设计之基于springboot的地方美食分享系统

计算机毕业设计之基于springboot的地方美食分享系统

当前,由于人们生活水平的提高和思想观念的改变,然后随着经济全球化的背景之下,互联网技术将进一步提高社会综合发展的效率和速度,互联网技术也会涉及到各个领域,于是传统的管理方式对时间、地点的限制太多,…

2026/7/29 1:39:56 阅读更多 →
rag学习

rag学习

RAG的基本流程分片主要用于把一篇文档,切分为多个部分可以按字数分,段落分,章节分,页数分等等。向量数据库1.通过Embedding的方式,把分片出来的各段文本转换为向量2.把片段文本对应的向量存入向量数据库中Embedding方式…

2026/7/29 1:39:56 阅读更多 →
Java 并发编程:线程安全队列全解 —— 阻塞与非阻塞实现原理及源码深度剖析

Java 并发编程:线程安全队列全解 —— 阻塞与非阻塞实现原理及源码深度剖析

在 Java 并发编程体系中,线程安全队列是实现生产者 - 消费者模式、任务分发、流量缓冲、线程解耦的核心组件,也是 java.util.concurrent(JUC)包的核心基石。根据实现机制的不同,线程安全队列可分为两大流派&#xff1a…

2026/7/29 1:39:56 阅读更多 →
为什么92%的AI电商设计项目失败?——3大认知陷阱与48小时急救修复方案

为什么92%的AI电商设计项目失败?——3大认知陷阱与48小时急救修复方案

更多请点击: https://kaifayun.com 第一章:为什么92%的AI电商设计项目失败?——3大认知陷阱与48小时急救修复方案 行业调研数据显示,近一年内启动的AI电商设计项目中,高达92%未能交付预期商业价值。失败主因并非技术…

2026/7/29 1:39:56 阅读更多 →
【年度总结】用了半年AI Agent,这10条经验让我从怀疑到离不开——附完整工具链

【年度总结】用了半年AI Agent,这10条经验让我从怀疑到离不开——附完整工具链

文章目录 写在前面 系列写了11篇,从CRUD框架到MCP协议到Redis到RabbitMQ到Elasticsearch到Prometheus,每篇都是一个技术点的深度拆解。今天换个视角——不聊具体代码,聊这半年踩出来的10条核心经验。 如果你刚开始用AI Agent,或者…

2026/7/29 1:39:56 阅读更多 →
# 鸿蒙 HarmonyOS 应用开发实战(第26期)|石头剪刀布(Rock-Paper-Scissors)— 游戏逻辑与胜负判定精讲

# 鸿蒙 HarmonyOS 应用开发实战(第26期)|石头剪刀布(Rock-Paper-Scissors)— 游戏逻辑与胜负判定精讲

一、应用概述 石头剪刀布(Rock-Paper-Scissors) 是一款经典的人机对战游戏,用户与电脑进行石头剪刀布对决。应用提供了直观的图形化选择按钮(✊✌️🖐️),玩家点击选择后,电脑随机出…

2026/7/29 1:38:56 阅读更多 →

日新闻

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:00:23 阅读更多 →
AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础 在上一期「AI编程系列」中,我们学习了如何构建一个基础的 AI 问答系统,通过简单的输入输出让模型回应问题。但现实世界中的 AI 应用往往需要处理更复杂的场景:…

2026/7/29 0:00:23 阅读更多 →
AI智能体开发实战:从工具调用到企业级部署

AI智能体开发实战:从工具调用到企业级部署

1. 从被动问答到主动执行:AI Agent的范式转变过去两年,大语言模型最显著的应用形态是聊天机器人——用户提问,AI回答。但真正的生产力革命发生在2023年下半年:当AI学会主动调用工具完成任务时,生产力工具的历史被彻底改…

2026/7/29 0:00:23 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻