设计1.0 -- iterator 和const_iterator底层的模拟实现

手写C++双向链表:从迭代器到哨兵节点的底层实现 双向链表是C++ STL中list容器的核心数据结构,其本质是通过指针维护前后节点关系的动态线性结构。理解其原理需掌握内存布局、迭代器语义与哨兵机制三大关键——前者决定访问效率,后者保障接口一致性与异常安全。技术价值体现在O(1)头尾操作、强迭代器稳定性及splice等无拷贝拼接能力,广泛应用于嵌入式内存管理、游戏对象池、定制容器扩展等对控制粒度要求严苛的工程场景。本文以最小可行代码实现MyList,聚焦list最核心的7个接口及其底层指针操作逻辑。 阅读详情

本文概要:

本文主要是模拟实现STL中迭代器和const迭代器的,主要阐述的一个问题就是,为什么我们在设计迭代器的时候需要使用三个模板参数呢

在设计迭代器的时候,我们有下面的代码

#include<iostream>
using namespace std;

template<class T>
struct _ListNode
{
    _ListNode<T>* _next;
    _ListNode<T>* _prev;
    T _data;
    _ListNode(T d = 0)
        :_data(d)
        , _next(NULL)
        , _prev(NULL)
    {}
};


//这个T标记的是维护的数据类型,Ref是引用,这个引用是对数据的引用,就是这里面data的引用
//Ptr是指针,这个指针也是指向数据data的指针这两个模板类型我们可以在
//List这个类里面使用,因为在编写List_Iterator的时候,会经常使用Ref和Ptr
template<class T, class Ref, class Ptr>
class List_Iterator
{
    typedef _ListNode<T> Node;
    typedef List_Iterator<T, Ref, Ptr> Self;   //这个地方写的 有点失误了,就是把List_Iterator的单词写错了
public:
    List_Iterator(Node* it)
        :_it(it)
    {}

    //List_Iterator& operator++()
    Self& operator++()
    {
        _it = _it->_next;
        return *this;
    }

    Self operator++(int)    //注意前置++返回的是引用,而后置++返回的是Self
    {
        Node* tmp = _it;
        _it = _it->_next;
        return tmp;
    }

    //T& operator*()
    Ref operator*()
    {
        return _it->_data;
    }

    bool operator!=(const Self& it)
    {
        return _it != it._it;    //一开始写这个!=运算符重载的时候也出现了错误,就是我一开始是拿this和&it比
                                //这显然是不对的,两个迭代器不可能是相等的,所以这个时候应该是拿
                                //这两个迭代器所指向的内容来比较,就是那他们的成员变量来 进行比较才正确
    }

private:
    Node* _it;
};


//这里我们需要做一个修改就是,我们需要把这个链表定义成一个双向的有头的循环链表
//这个工作就是要在构造函数的时候去做了
//所以这里_tail就不需要了



//有头结点,_head维护了一个头结点,但是这个节点不放置任何的数据,因为这样在后面的增删查改的时候使用的时候会非常的方便
template<class T>
class _List
{
    typedef _ListNode<T> Node;

public:
    typedef List_Iterator<T, T&, T*> Ierator;
    //const迭代器
    typedef List_Iterator<T, const T&, const T*> Const_Ierator;

    _List()
        :_head(new Node)   //这里报了一个错误就是,没有合适的构造函数可以使用,原因是我上面写_ListNode的时候
        //传参了,但是这里没有传参数,所以我上面的额时候把传递的参数默认为d = 0这个时候就算是我不传递参数
        //也没有什么问题了
        //  , _tail(_head)
    {
        _head->_next = _head;
        _head->_prev = _head;
    }



    Node* begin()
    {
        if (_head->_next == _head)   //这里做了一个判断就是当我们的链表是空的时候,就不能直接返回next
        {
            return NULL;
        }
        return _head->_next;
    }



    Node* end()
    {
        if (_head->_next == _head)
        {
            return NULL;
        }
        return _head;
    }


    void Pushback(const T& data)
    {
        Node* cur = new Node(data);
        cur->_prev = _head->_prev;
        _head->_prev = cur;
        cur->_next = _head;
        cur->_prev->_next = cur;

    }

    void Print()
    {
        Const_Ierator it = begin();   //这个原因是,我们的begin不是 const的,但是我们的const_ietator是const的
        while (it != end())
        {
            cout << *it << endl;
            it++;
        }
    }
private:
    Node* _head;
//  Node* _tail;
};

void TestList()
{
    _List<int> l;
    l.Pushback(0);   //一开始的时候,我这里设置的这个参数是引用,这个时候是辩不过的,因为我们的0是在常量区的
    l.Pushback(1);
    l.Pushback(2);

    /*_List<int>::Ierator it = l.begin();
    cout << *it << endl;
    ++it;
    cout << *it << endl;
    ++it;
    cout << *it << endl;*/
    _List<int>::Ierator it = l.begin();
    *it = 5;
    l.Print();

}




这里想重点比较一下普通迭代器和const迭代器,这里我们想看我们的普通迭代器的定义,

template<class T, class Ref, class Ptr>
class List_Iterator
{
    typedef _ListNode<T> Node;
    typedef List_Iterator<T, Ref, Ptr> Self;   //这个地方写的 有点失误了,就是把List_Iterator的单词写错了
public:
    List_Iterator(Node* it)
        :_it(it)
    {}

    //List_Iterator& operator++()
    Self& operator++()
    {
        _it = _it->_next;
        return *this;
    }

    Self operator++(int)    //注意前置++返回的是引用,而后置++返回的是Self
    {
        Node* tmp = _it;
        _it = _it->_next;
        return tmp;
    }

    //T& operator*()
    Ref operator*()
    {
        return _it->_data;
    }

    bool operator!=(const Self& it)
    {
        return _it != it._it;    //一开始写这个!=运算符重载的时候也出现了错误,就是我一开始是拿this和&it比
                                //这显然是不对的,两个迭代器不可能是相等的,所以这个时候应该是拿
                                //这两个迭代器所指向的内容来比较,就是那他们的成员变量来 进行比较才正确
    }

private:
    Node* _it;
};

这里只是一个普通的迭代器的实现,一开始我一直疑惑的一个问题就是,为什么这里在设计的时候需要设计三个模板参数 呢,因为是为了实现迭代器的复用,这个时候还是需要看一下我们的list中对于迭代器的使用

class _List
{
    typedef _ListNode<T> Node;

public:
    typedef List_Iterator<T, T&, T*> Ierator;
    //const迭代器
    typedef List_Iterator<T, const T&, const T*> Const_Ierator;

    _List()
        :_head(new Node)   

这里我只截图了迭代器的一部分,想看全部的可以从上面来看,这里需要定义一个普通的迭代器的时候,使用typedef List_Iterator

Ref operator*()
    {
        return _it->_data;
    }

因为我们在list中使用的时候是按照下面的形式进行组织的

typedef List_Iterator<T, const T&, const T*> Const_Ierator;

所以在上面的那个Ref operator*()里面 返回值就变成了const的,这个时候const_iterator所指向的内容就不可变了

C++ STL list模拟实现:从节点设计到迭代器封装与内存管理 在C++标准模板库(STL)中,容器是泛型编程的核心组件,它们通过封装底层数据结构,提供统一、安全的接口。链表作为一种基础数据结构,其双向链表实现(如std::list)支持高效的元素插入与删除,这源于其节点通过指针连接、无需连续内存存储的原理。这种设计在需要频繁增删元素的场景(如事件处理、缓存系统)中具有重要技术价值。理解其内部机制,尤其是迭代器的封装与内存管理,能帮助开发者编写更高效、健壮的代码。本文通过模拟实现一个简化版list,深入探讨节点结构、哨兵节点、迭代器类设计及拷贝控制等关键实现细节,并解析 阅读详情

相关推荐

JavaScript迭代协议详解:Iterable与Iterator原理及实战

Iterable(可迭代对象)和 Iterator(迭代器)是 JavaScript 中支撑 for...of、扩展运算符、Array.from 等语法的底层协议机制。其核心原理在于:Iterable 对象必须实现 Symbol.iterator 方法,该方法返回一个符合 Iterator 协议的对象;而 Iterator 对象必须提供 next() 方法,返回 { value, done } 结构。这一协议赋予了数据遍历行为的标准化、可组合性与惰性求值能力,技术价值体现在解耦数据消费与获取逻辑、支持流式/

weixin_33796205的博客 503

c++迭代器中的 iterator和const_iterator

c++迭代器中的iterator和const_iterator介绍

goodnessg的博客 1080

基于深度学习的UWB门禁检测

针对基于UWB技术智能门禁管理系统,由于测距误差或非视距原因导致门禁产生不合理动作的现象。分析如何采用基于深度学习的方法,通过对TWR测距数据、TWR监听数据、到达角度差(PDOA)、信道脉冲响应(CIR)等数据维度进行深度学习,利用 TensorFlow建立相应的推导模型,对卡片姿态进行更加精准可靠的检测,从而更好完成闸机开合控制。

tenth_quadrant的博客 2027

双链表的设计和实现

双链表C++实现

weixin_53254469的博客 405

MATLAB 论文复现——含氢综合能源系统多目标最优折中分布鲁棒低碳调度

提出基于多目标决策理论和逼近理想解排序技术,构造综合考虑系统调度的经济性、低碳性和鲁棒度的多目标最优折中函数,从而建立含氢综合能源系统多目标最优折中分布鲁棒低碳调度模型,可快速准确地获得兼具经济性、低碳性和鲁棒性的含氢综合能源系统优化调度方案。[1]孙惠娟,胡紫平,彭春华,等.含氢综合能源系统多目标最优折中分布鲁棒低碳调度[J/OL].电力自动化设备,1-13[2024-07-26].https://doi.org/10.16081/j.epae.202406003.关键词: 综合能源系统;

sjr1478的博客 410

Python表白代码:“ 星光月夜烟花皆归你,我也归你”(满天烟花盛开、附番外玫瑰)

导语 "慢品人间烟火色 闲观人间岁月长" ———致自己​​​ ​ ???? 遇见我以后,我们的故事就开始了,愿你历经山河,仍觉得人间值得????。 ​ 星光月夜烟花皆归你,我也归你。关于烟花????大家都​知道多少?有多少表白故事情节都发生在烟 花下,想必木木子????不用说大家也知道叭~​​ 今天这则小短文就是关于烟花的故事!你准备好跟我一起进入烟花的世界了嘛? ​正文 “每一句文案,都有一个故事,你仔细听” ​ 1)环境安装???? 准备好:.

顾木子吖的博客 5万+

迭代器const_iterator和iterator的实现方法与迭代器比较运算符的优化

最近在跟着侯捷老师的《STL源码剖析》学习SGI STL的源码,发现const_iterator和iterator的实现细节实在巧妙,想写一篇文章跟大家分享一下。

weixin_51829359的博客 1750

贝塞尔曲线基础

贝塞尔曲线于1962年由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau演算法开发,以稳定数值的方法求出贝兹曲线。

YiYeZhiNian的博客 2045

分块刨析从函数原型到分块实现C++STL(vector)

分块刨析从函数原型到分块实现C++STL(vector)

小杰312的博客 2941

Mac 下 OpenClaw 安装全记录:从零到一的保姆级图文教程

本文主要介绍了Mac 下 OpenClaw 安装全记录:从零到一的保姆级图文教程,希望能对学习使用OpenClaw 的同学们有所帮助。 文章目录 1. 背景 2. 安装教程 2.1 安装OpenClaw 2.2 配置模型 2.3 对话 3. 后续使用步骤 4. 关闭程序

weixin_43178406的博客 11万+

杰理可视化SDK开发-杰理AC1123N芯片SDK开发笔记合集

该文档主要描述 AC112N开发相关的使用说明和注意事项,收集并持续更新开发调试过程中的相关疑问和解答,对SDK介绍文档做一个补充说明。写作人:李永奉,参考项目MD-026H; AC112N-SDK项目帮助文档在杰理开发者平台(JL DP)'帮助'处进入,如本文档有与后续帮助文档或工具注释说明冲突,以后者为标准。

李永奉的博客 181

C++进阶-------STL标准模板库(1)

C++ STL标准模板库(一) STL 是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成,其中后面 4 部分是为前 2 部分服务的,它们各自的含义如表 1 所示。 容器类 简单的理解容器,它就是一些模板类的集合,但和普通模板类不同的是,容器中封装的是组织数据的方法(也就是数据结构)。STL 提供有 3 类标准容器,分别是序列容器、排序容器和哈希容器,其中后两类容器有时也统称为关联容器。它们各自的含义如表所示。 迭代器 无论是序列容器还是关联容器,最常做的操作无疑是遍历容器中存

weixin_33460831的博客 545

计算机组成原理(第三版)唐朔飞-第九章控制单元的功能-课后习题

计算机组成原理(第三版)唐朔飞-第九章控制单元的功能-课后习题

weixin_45735391的博客 4万+

C++STL map和set的底层理解及其模拟实现【保姆式教学】

set文档介绍map的文档简介// 该节点的左孩子 AVLTreeNode < T > * _pRight;// 该节点的右孩子 AVLTreeNode < T > * _pParent;// 该节点的双亲 T _data;int _bf;// 该节点的平衡因子 };// 节点的颜色 enum Color {// 红黑树节点的定义 template < class ValueType > struct RBTreeNode {

qq_54626677的博客 2766

GameFramework框架详解之 Network网络框架

NetworkManager只负责维护NetworkChannel,实际的有种我们简历网络连接的也是NetworkChannel作为一个网路频道,这样管理起来比较方便,比如:一个游戏可能有多个网络连接,那么我们建立多个网络频道即可,或者当我们一个网络频道断线后,我们可以直接再新建一个,防止数据混乱。/// /// 网络管理器。/// /// 网络频道。/// 用户自定义网络错误事件。/// 检查是否存在网络频道。/// 获取网络频道。/// 获取所有网络频道。

TxNet 3366

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

c++stl 之list的底层理解及其模拟实现

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。

qq_54626677的博客 611

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

STL-list类的模拟实现

本文详细介绍了如何实现一个类似STL的双向循环链表list容器。主要内容包括:1. 节点结构设计,使用双向指针实现高效操作;2. 迭代器实现,通过运算符重载提供类指针接口;3. 核心容器功能实现,包括构造/析构、插入/删除操作;4. 深拷贝处理,解决浅拷贝问题;5. 常量迭代器实现,支持只读访问;6. 常用功能扩展如size()、empty()等。通过多个测试案例验证了容器的正确性,完整代码展示了工业级链表容器的实现方法,包括哨兵节点、内存管理、迭代器设计等关键技术。

2501_93269390的博客 449

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

C++的list的const_iterator实现的关键点理解

相反的,如果是const list<T>对象,那么其迭代器将可读不可写,即该const list<T>对象可读不可以写。其实这三个参数是为了实现const_iterator而准备的,这三个模板参数有两种形态分别是<T,T&,T*>和<T,const T&,const T*>分别对应普通list对象和const list对象的迭代器,前者的迭代器可以对list<T>对象可读可写,后者的迭代器对list<T>对象仅仅可读。

Huangxingnan1的博客 656

vector模拟实现及个人问题总结

因为迭代器不一定是T,假如vector里面存的是int,T就是int*,但是我在构造的时候想把给double传给类型传给这个vector,一般情况下,double类型是可以隐式转化为int类型的,只是精度会降低。比如调用insert时,给定一个pos定位原对象空间的某个位置,准备插入时发现空间不够,于是创建了一个新的空间,此时Pos并没有指向新空间对应的位置,对pos进行赋值是没有意义的。,有可能产生其他的效果。,但是当有模板构造函数时,模板构造函数的匹配程度更高(因为不需要类型转换,两个参数都是。

Titan2024的博客 698

《链表的优雅封装:C++ list 模拟实现与迭代器之美》

摘要: 本文详细分析了C++中list的实现原理及其特性。list底层采用双向链表结构,相比数组结构的vector和string,其优点包括:插入/删除操作仅需调整指针(时间复杂度O(1)),迭代器稳定性(插入/删除不导致其他迭代器失效)。缺点是无法随机访问(需遍历),且迭代器需封装指针以支持++、*等操作。 实现分为三类: 节点类(list_node):存储数据及前后指针; 链表类(list):维护哨兵节点_head及大小_size,提供push_back、insert等方法; 迭代器类:封装节点指针,重

sdm070427的博客 668

【C++】反向迭代器:反向迭代器的底层认识与模拟实现

本文介绍了C++中反向迭代器的实现原理,通过适配器设计模式复用普通迭代器作为底层,结合运算符重载实现与迭代器相反的遍历方向。反向迭代器的核心在于封装迭代器类型并重载操作符,使其++对应迭代器的--,从而反向遍历容器。文章还解释了operator*返回前一个位置值的原因,以保持rbegin与end对称的逻辑关系。最后展示了反向迭代器在类中的实例化方式,强调其本质是通过封装普通迭代器实现反向遍历功能。

2502_94043640的博客 431

【C++】vector的模拟实现详解(二)

C++ vector模拟实现详解(二) 本文详细介绍了如何模拟实现C++标准库中的vector容器。主要内容包括: vector的整体设计: 使用类模板实现泛型 通过三个指针(_start、_finish、_end_of_storage)管理连续空间 解释指针之间的关系和空间管理原理 构造与析构: 默认构造函数使用=default生成 析构函数负责释放动态申请的内存 迭代器实现: 使用原生指针实现普通迭代器和const迭代器 提供了begin()和end()方法 实现const对象的遍历功能 容量相关接口:

qeen87的博客 447

C++迭代器(Iterator)详解:从原理、使用方法到底层实现全面掌握

函数作用begin()返回头迭代器end()返回尾后迭代器rbegin()返回反向头rend()返回反向尾cbegin()const开始cend()const结束迭代器是STL中用于访问容器元素的一种对象,本质是对指针的封装。

m0_74978334的博客 277

C++ vector模拟实现:从三指针到移动语义的底层原理剖析

在C++编程中,动态数组是管理连续内存数据的基础数据结构,其核心原理在于通过指针运算实现高效的随机访问和动态扩容。理解这一原理对于掌握内存管理、RAII(资源获取即初始化)和异常安全等C++核心概念至关重要。从工程实践角度看,手动实现标准库容器能够深入理解迭代器失效、模板编程和拷贝控制等底层机制,提升代码调试和性能优化能力。本文以C++标准库中的vector为蓝本,通过模拟实现其动态扩容策略、三指针内存模型以及移动语义支持,具体探讨了reserve与resize的内存分配逻辑、push_back与inser

weixin_33713707的博客 306

【C++】list 的使用及迭代器底层详解

详细讲解了 list 迭代器的底层实现,充分展示了其与string、vector迭代器的不同

HDSTQTW的博客 1480

对于模拟实现C++string类的详细解析—上

本文详细解析了C++中string类的底层实现原理,包括成员变量设计、构造函数、拷贝构造、运算符重载等核心功能。重点剖析了现代"拷贝-交换"写法相对传统写法的优势,如异常安全、代码复用等。同时强调了编程中合理使用const的重要性,包括参数保护和成员函数标记。此外,文章还介绍了迭代器的本质与实现、c_str函数的作用等关键技术点。通过模拟实现string类,帮助读者深入理解C++内存管理和对象生命周期的底层机制,为后续学习更复杂的字符串操作打下基础。

2503_92929084的博客 902
上一篇: 继承和多态 1.0 -- 继承概念(is-a、has-a,赋值兼容规则,隐藏重定义)
下一篇: STL模拟实现1.0 -- list和iterator模拟实现和简单分析
NeilZhy
博客等级 码龄11年 175粉丝 145原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值