手撕STL:list底层结构与迭代器实现
本文代码已同步Github一、底层源码分析1、源码剖析通过上一篇对vector的学习我们知道其底层是通过三个指针来充当迭代器下面我们来看一下list的底层是怎么设计的同样使用g中的SGI版本来观察先来看说明文档发现依据是多个头文件配合的形式那么核心文件便是stl_list.h我们来看一看发现和vector不同的是list里面有多个类比如list_node ,list_iterator,这些简单看一下类的名称及成员变量就会知道list_node是节点存储的是节点的信息看来底层确实是由一个双向链表来实现的list_iterator就是迭代器有一个list_node*的指针我们再往下看看还有没有其他的类还有一个类类名为list里面有一个list_node*的指针2、不同类之间的关系下面我们来理一理三个类之间的关系list用来控制整个链表无论是push_back还是insert等操作都通过list中的成员函数来实现而list_iterator是迭代器用来定位和访问通过重载–等操作符将迭代器封装成类似指针的效果最后的list_node就是一个一个的节点了好了根据上述对底层源码的简单分析之后我们来搭一下基础框架二、类模板框架搭建1、结构实现注意⚠️我们实现的仅仅是基础版为方便起见我们加入成员变量_sizenamespacestl{//节点templateclassTstructlist_node{list_node(constTdataT()):_data(data),_prev(nullptr),_next(nullptr){}T _data;list_nodeT*_prev;list_nodeT*_next;};//迭代器templateclassTstructlist_iterator{typedeflist_nodeTNode;typedeflist_iteratorTSelf;list_iterator(Node*node):_node(node){}Node*_node;};templateclassTclasslist{public:typedeflist_nodeTNode;typedeflist_iteratorTiterator;private:Node*_head;size_t _size;public:};}下面我们来写list的默认构造函数分析首先要new一个节点这个节点即为哨兵位接着修改指针的指向并给_size赋值list(){_headnewNode;_head-_prev_head;_head-_next_head;_size0;}2、基础接口实现我们先来实现size和emptysize_tsize(){return_size;}boolempty(){return_size0;}接着来实现begin和end单参数构造函数可以进行隐式类型转换我们直接返回节点的地址即可iteratorbegin(){return_head-_next;}iteratorend(){return_head-_prev-_next;}三、迭代器实现1、iterator上一篇对list接口的介绍中我们知道list的迭代器是双向迭代器也就是说只能,--但是对于链表来说由于不是顺序存储因此对于普通指针无论是还是–之后都无法到达下一个节点此时我们就需要对运算符进行重载a、代码实现首先来分析怎样重载迭代器的遍历是通过解引用来得到信息因此需要重载*运算符函数返回类型是T分析逻辑在写list_iterator时迭代器类的构造函数就会将_node指向迭代器变量所指的位置那么直接返回_node-_data即可Toperator*(){return_node-_data;}对于–我们的目的是能够到达下一个节点返回的是节点的地址即T*而_node中就存储着前一个节点和下一个节点的地址直接返回即可Selfoperator(){_node_node-_next;return*this;}Selfoperator(int){Selftmp(*this);_node_node-_next;returntmp;}Selfoperator--(){_node_node-_prev;return*this;}Selfoperator--(int){Selftmp(*this);_node_node-_prev;returntmp;}最后再来实现一下和!booloperator(constSelfs)const{return_nodes._node;}booloperator!(constSelfs)const{return_node!s._node;}b、测试为了便于测试我们先实现push_back分析先new节点接着修改指针指向即可templateclassTvoidlistT::push_back(constTval){Node*newnodenewNode(val);_head-_prev-_nextnewnode;newnode-_prev_head-_prev;newnode-_next_head;_head-_prevnewnode;_size;}下面来测试一下对于内置类型没有问题接着来测试一下自定义类型编译报错问题就在于这个*it解引用之后拿到的是A的对象或者引用因此需要用.来访问这样显得有点麻烦不如直接重载-运算符返回_data的地址这样直接返回一个指针再用一个-即可解决注意两个-会省略成一个-T*operator-(){return_node-_data;}2、const_iterator首先思考一下const迭代器和普通迭代器的区别是什么const迭代器到底是迭代器本身不能被修改还是所指向的内容不能被修改答案显然是所指向的内容不能被修改在前面的vector中我们直接在begin,end的返回值改成const_iterator通过const成员函数重载同时函数后面也加上const这样返回值的类型就是const T ptr const,返回一个只读引用解引用之后只读避免迭代器所指向内容被修改而在list中显然不能直接在begin,end前加上const了因为这两个函数返回的只是第一个有效位置和最后一个位置的下一个位置的迭代器就算加上const返回值类型为const iterator对迭代器访问没有作用关键在于*运算符限制*的返回类型即可避免迭代器所指向的内容被修改a、代码实现理解完const_iterator之后发现与iterator的不同就是*运算符的不同那么该怎么写呢我们可以选择封装一个const_iterator类里面将*的返回值加上const即可//const_iteratortemplateclassTstructlist_const_iterator{typedeflist_nodeTNode;typedeflist_const_iteratorTSelf;list_const_iterator(Node*node):_node(node){}Node*_node;constToperator*()const{return_node-_data;}constT*operator-()const{return_node-_data;}Selfoperator(){_node_node-_next;return*this;}Selfoperator(int){Selftmp(*this);_node_node-_next;returntmp;}Selfoperator--(){_node_node-_prev;return*this;}Selfoperator--(int){Selftmp(*this);_node_node-_prev;returntmp;}booloperator(constSelfs)const{return_nodes._node;}booloperator!(constSelfs)const{return_node!s._node;}};b、测试我们通过一个打印容器的函数模板来测试templateclassConvoidprint_container(constConcon){for(constautoe:con){std::coute ;}std::coutstd::endl;}3、优化对于iterator类以及const_iterator类两个类大体上高度相似真的有必要再重新封装一个类吗我们来看源码是怎么做的发现源码将模板参数设计成了三个参数并且也没有额外的类此时我们来分析一下Ref表示引用Ptr表示指针也就是说给list_iterator类的参数不同就实例化出不同的类我们来分析为什么给普通迭代器传的是T,T,T*而const迭代器则是T,const T,const T*?通过成员函数来分析主要来看*和-如果是普通迭代器对于*,我们返回的是Ref,而此时Ref就是T对于-我们返回的是Ptr此时Ptr就是T*完全符合情况如果是const迭代器对于*,我们返回的是Ref,而此时Ref就是const T对于-我们返回的是Ptr此时Ptr就是const T*同样完全符合情况因此源码直接设计方式非常优雅简洁我们也同样采用这种方式需要注意的是在list中对不同参数均需做出声明//迭代器//templateclass TtemplateclassT,classRef,classPtrstructlist_iterator{typedeflist_nodeTNode;typedeflist_iteratorT,T,T*iterator;typedeflist_iteratorT,constT,constT*const_iterator;typedeflist_iteratorT,Ref,PtrSelf;list_iterator(Node*node):_node(node){}Node*_node;Refoperator*(){return_node-_data;}Ptroperator-(){return_node-_data;}其他成员函数保持原样即可四、核心接口实现1、insert分析逻辑注意返回值是迭代器指向第一个被插入的元素接着pos是迭代器在pos之前插入数据templateclassTlistT::iteratorlistT::insert(iterator pos,constTval){Node*newnodenewNode(val);Node*curpos._node;Node*prevcur-_prev;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;prev-_nextnewnode;_size;returnnewnode;}来测试一下2、erase接着来看eraseiteratorerase(iterator position);iteratorerase(iterator first,iterator last);分析删除pos位置的节点更改指针指向即可最后返回pos位置的下一个节点的迭代器templateclassTlistT::iteratorlistT::erase(iterator pos){Node*curpos._node;Node*prevcur-_prev;Node*nextcur-_next;prev-_nextnext;next-_prevprev;deletecur;curnullptr;--_size;returnnext;}来测试一下3、push_front、pop_front、pop_back这几个均直接复用代码即可voidpush_front(constTval){insert(begin(),val);}voidpop_front(){erase(begin());}voidpop_back(){erase(--end());}五、完善结构1、构造函数下面我们实现list里面的构造函数default (1)explicit list (const allocator_type alloc allocator_type());fill (2)explicit list (size_type n, const value_type val value_type(), const allocator_type alloc allocator_type());range (3)template class InputIterator list (InputIterator first, InputIterator last, const allocator_type alloc allocator_type());copy (4)list (const list x);目前只实现了默认构造函数我们依次来实现对于n个val构造注意⚠️先创建出哨兵位再复用push_back直接将创建哨兵位封装成函数voidempty_init(){_headnewNode;_head-_prev_head;_head-_next_head;_size0;}//n个val构造list(size_t n,constTvalT()){//先创建头节点empty_init();for(size_t i1;in;i){push_back(val);}}对于迭代器区间构造首先创建出哨兵位接着同样复用push_back//迭代器区间构造templateclassInputIteratorlist(InputIterator first,InputIterator last){//先创建头节点empty_init();autoitfirst;while(it!last){push_back(*it);it;}}对于拷贝构造同样先创建哨兵位接着复用push_back即可//拷贝构造list(constlistlt){//先创建头节点empty_init();for(autoe:lt){push_back(e);}}我们来测试一下2、赋值运算符voidswap(listlt){std::swap(_head,lt._head);std::swap(_size,lt._size);}//现代写法listoperator(list lt){swap(lt);return*this;}来测试一下3、析构函数最后来看析构函数分析逐个节点释放最终释放哨兵位不妨将逐个节点释放封装成函数voidclear(){autoitbegin();while(it!end()){iterase(it);}}~list(){clear();delete_head;_headnullptr;_size0;}六、总结至此我们已经越过了STL的两座大山——vector和list下面我们来总结一下两者的区别vectorlist底层动态数组双向链表随机访问O(1)O(n)插入删除中间慢快空间连续不连续迭代器随机迭代器双向迭代器如果觉得有帮助可以关注Github项目持续更新

相关新闻

ChatBI落地的最大阻力不是技术:‘数据找人‘场景下的权限与口径治理

ChatBI落地的最大阻力不是技术:‘数据找人‘场景下的权限与口径治理

导语 ChatBI(对话式BI,即用自然语言提问即可获取数据分析结果的工具)项目失败率最高的环节,不是模型选型,也不是语料准备,而是"数据找人"模式下被忽视的两条治理线——行级权限(控制&…

2026/8/11 2:29:03 阅读更多 →
Zotero PDF Translate:学术研究者的多语言文献处理完整解决方案

Zotero PDF Translate:学术研究者的多语言文献处理完整解决方案

Zotero PDF Translate:学术研究者的多语言文献处理完整解决方案 【免费下载链接】zotero-pdf-translate Translate PDF, EPub, webpage, metadata, annotations, notes to the target language. Support 20 translate services. 项目地址: https://gitcode.com/gh…

2026/8/11 2:28:03 阅读更多 →
前端工程师的AI Agent转型红利:告别35岁焦虑,拿高薪!

前端工程师的AI Agent转型红利:告别35岁焦虑,拿高薪!

最近很多粉丝找我咨询想转行做 AI Agent 开发,吐槽说前端工程师已经找不到工作了。 就我自身经验来说,AI的冲击确实对传统研发人员“打击”很大,稀释了很多前端开发的岗位,现在随便招聘网站一打开,90%的研发岗位都要求…

2026/8/11 2:28:03 阅读更多 →

最新新闻

美客多自养号评测体系搭建与运营优化实战

美客多自养号评测体系搭建与运营优化实战

1. 项目概述:美客多平台与买家号评测的价值 美客多作为拉美地区最大的电商平台,其运营模式对跨境卖家而言既是机遇也是挑战。在这个平台上,真实的买家行为数据就像黄金一样珍贵——它能告诉你哪些产品描述真正打动消费者、哪些促销策略最有效…

2026/8/11 3:24:22 阅读更多 →
ABB 变频器外形机架尺寸与柜体安装要点

ABB 变频器外形机架尺寸与柜体安装要点

摘要:电气选型很多工程师只看功率、电流参数,忽略机架 Frame (R) 尺寸,控制柜图纸画完,到货发现装不进去,散热空间不足。本文梳理 ABB 主流 ACS510、ACS550、ACS355、ACS880 壁挂机型机架代号 R0‑R6,外形尺…

2026/8/11 3:24:22 阅读更多 →
reboot 与 restart 的区别

reboot 与 restart 的区别

reboot 与 restart 的区别 reboot 和 restart 都可以指重新启动电脑,几乎可以互换reboot 更偏向技术术语,例如,IT 管理员说:我需要 reboot 一下服务器restart 更偏向日常用语,例如,教家人:先 re…

2026/8/11 3:24:22 阅读更多 →
阅读APP书源配置指南:3步打造专属小说图书馆

阅读APP书源配置指南:3步打造专属小说图书馆

阅读APP书源配置指南:3步打造专属小说图书馆 【免费下载链接】Yuedu 📚「阅读」自用书源分享 项目地址: https://gitcode.com/gh_mirrors/yu/Yuedu 还在为找不到心仪的小说资源而烦恼吗?想要在阅读APP中畅享海量免费小说却不知从何入手…

2026/8/11 3:24:22 阅读更多 →
用 CoordClaw 基于管理学多智能体系统搭建一支“个人投资团队“

用 CoordClaw 基于管理学多智能体系统搭建一支“个人投资团队“

一个人管钱,却要同时扮演策略师、行业研究员、风控官、量化工程师——这是个人投资者最真实的困境。把全部希望押在一个"够大的大模型"上,让它一口气产出选股、回测、风控结论,结果往往是:它很自信,但错得一…

2026/8/11 3:24:22 阅读更多 →
SAP FICO税务配置实战:从税码、科目规则到OB40的完整落地指南

SAP FICO税务配置实战:从税码、科目规则到OB40的完整落地指南

这类工具最值得先看的不是功能列表,而是能不能在普通环境里稳定跑起来。SAP FICO里的税码和科目规则,特别是OB40这个配置点,是很多项目上线和月结时出问题的重灾区。它直接关系到财务凭证能不能正确生成、税能不能算对、报表数据准不准。很多…

2026/8/11 3:23:22 阅读更多 →

日新闻

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trending/vi/v…

2026/8/11 0:00:02 阅读更多 →
前后端分离项目中控制台与接口工具数据差异排查指南

前后端分离项目中控制台与接口工具数据差异排查指南

1. 问题现象解析:控制台与Apifox的数据差异 最近在调试一个前后端分离项目时,遇到了一个典型问题:后端服务在本地开发环境控制台能正常输出查询数据,但通过Apifox测试时却返回空结果。这种"控制台有数据,接口工具…

2026/8/11 0:00:03 阅读更多 →
AI编程实战:从Claude Code踩坑到游戏开发入门

AI编程实战:从Claude Code踩坑到游戏开发入门

1. 从“AI能帮我做游戏”到“AI让我重新学编程”最近身边不少朋友,尤其是一些非技术背景、但对游戏开发有浓厚兴趣的朋友,都在问我同一个问题:“听说现在用Claude Code这种AI编程工具,小白也能做游戏了,是真的吗&#…

2026/8/11 0:00:03 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/11 1:08:05 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/11 1:08:05 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/11 1:08:05 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/10 17:07:33 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/11 1:08:06 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/10 17:07:33 阅读更多 →