C++ STL 容器 list

目录

  • 1. list 对象
  • 2. list 迭代器
    • 2.1 实现
    • 2.2 迭代器失效


本文测试环境为 gcc 13.1

1. list 对象

std::list 底层是一个双向循环链表

list 对象本身包含一个头节点,通过指针指向元素节点,节点定义如下

在这里插入图片描述
头节点 header 和元素节点 node 都继承于基类 node_base

list<int> l;

所以 sizeof(l) = 8 + 8 + 8 = 24,一个 list 对象本身是 24 字节大小,头节点分配在栈上,而元素节点则通过 new 分配在堆上

具体模型如下图所示
在这里插入图片描述
可以看出,只要得到其中某个节点的迭代器,就可以以常数时间来进行插入和删除,但因为空间不连续,不支持快速随机访问

2. list 迭代器

2.1 实现

list 中的元素是不连续存储的,可不能像 vector 那样使用一个普通指针就能实现

想要通过这个迭代器访问每个元素,当然就需要 next 和 prev 指针了

这样,就可以使用 node_base 来实现,和 vector 一样,对这个进行封装,提供迭代器需要的功能

list 迭代器实现为双向迭代器,需要满足以下功能

运算说明
*解引用,得到迭代器指向元素的值
++it前置递增,将迭代器指向下一个元素
it++后置递增,将迭代器指向下一个元素,并返回指向当前元素的迭代器副本
- -it前置递减,将迭代器指向前一个元素
it- -后置递减,将迭代器指向前一个元素,并返回指向当前元素的迭代器副本
==,!=比较两个迭代器是否相等

很容易想到,++ 和 - - 不就对应 next 和 prev 吗,所以实现起来还是很简单的

那么怎么构造这个迭代器呢

vector 的迭代器最终就是一个指针,可以通过 start 指针来构造 begin(),finish 指针构造 end()

现在 list 的迭代器是对 node_base 的封装,是头节点和元素节点的基类,所以可以通过多态来实现,我们可以使用 head->next ,即第一个元素来构造 list 的 begin() 了,迭代器是用来遍历元素节点的,所以头节点作为 end(),刚好 head->prev 是最后一个元素,即 end() - 1 是最后一个元素

实现如下

template<typename _Tp>
struct _List_iterator
{typedef _List_iterator<_Tp>		_Self;typedef _List_node<_Tp>			_Node;typedef ptrdiff_t				difference_type;typedef std::bidirectional_iterator_tag	iterator_category;typedef _Tp				value_type;typedef _Tp*				pointer;typedef _Tp&				reference;//...	// The only member points to the %list element.__detail::_List_node_base* _M_node;
};

对 node_base 进行封装

构造

 _List_iterator() _GLIBCXX_NOEXCEPT: _M_node() { }explicit_List_iterator(__detail::_List_node_base* __x) _GLIBCXX_NOEXCEPT: _M_node(__x) { }

解引用

// Must downcast from _List_node_base to _List_node to get to value.
_GLIBCXX_NODISCARD
reference
operator*() const _GLIBCXX_NOEXCEPT
{ return *static_cast<_Node*>(_M_node)->_M_valptr(); }_GLIBCXX_NODISCARD
pointer
operator->() const _GLIBCXX_NOEXCEPT
{ return static_cast<_Node*>(_M_node)->_M_valptr(); }

++ 、–

_Self&
operator++() _GLIBCXX_NOEXCEPT
{_M_node = _M_node->_M_next;return *this;
}_Self
operator++(int) _GLIBCXX_NOEXCEPT
{_Self __tmp = *this;_M_node = _M_node->_M_next;return __tmp;
}_Self&
operator--() _GLIBCXX_NOEXCEPT
{_M_node = _M_node->_M_prev;return *this;
}_Self
operator--(int) _GLIBCXX_NOEXCEPT
{_Self __tmp = *this;_M_node = _M_node->_M_prev;return __tmp;
}

比较

_GLIBCXX_NODISCARD
friend bool
operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
{ return __x._M_node == __y._M_node; }#if __cpp_impl_three_way_comparison < 201907L
_GLIBCXX_NODISCARD
friend bool
operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
{ return __x._M_node != __y._M_node; }
#endif

对迭代器的解引用就是获取元素节点的 data 了,如果是对头节点的迭代器解引用,那么就会出问题了,如果元素也是 size_t 之类的数值类型的话,可能就没啥问题

2.2 迭代器失效

list 迭代器失效的话,那就是看这个 node_base 指针指向的节点是否可以正常使用了

1.插入元素

插入新元素会影响其他节点的地址和 data 吗,显然不会

2.删除元素

删除一个元素会影响其他节点的地址吗,当然也不会,但是这个要删除的节点的地址就不能正常引用了

因为 vector 连续存储和重新分配特点,迭代器失效问题就多一点,而 list 节点不连续,互不影响

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/630717.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用 Node.js 发送电子邮件全解和相关工具推荐

大多数Web应用程序都需要发送电子邮件。它可能用于注册、密码重置、状态报告&#xff0c;甚至是完整的市场营销活动&#xff0c;如新闻和促销。本教程解释了如何在Node.js中发送电子邮件&#xff0c;但其概念和挑战适用于您正在使用的任何系统。 你会在 npm 上找到大量与电子邮…

2024-4-15-ARM作业

实现字符串数据收发函数的封装 源代码&#xff1a; main.c #include "gpio.h"#include "uart4.h"int main(){uart4_config();while (1){// char agetchar();// putchar(a1);char s[20];gets(s);puts(s);//putchar(\n);putchar(\r);}return 0;}uart4.c …

JVM虚拟机(十一)CPU飙高的排查方案与思路

目录 一、排查方案与思路二、总结 一、排查方案与思路 1.一般我们查看 CPU 的使用情况&#xff0c;可以使用 TOP 命令&#xff1a; top执行结果如下所示&#xff0c;这里就可以按照 CPU 使用率进行排序。 2.通过 top 命令查看后&#xff0c;可以查看是哪一个 Java 进程占用 C…

前端三剑客 HTML+CSS+JavaScript ② HTML相关概念

他们这样形容我 是暴雨浇不灭的火 —— 24.4.18 学习目标 理解 HTML的概念 HTML的分类 HTML的关系 HTML的语义化 应用 HTML骨架格式 sublime基本使用 一、HTML初识 HTML指的是超文本标记语言&#xff0c;是用来描述网页的一种语言 超文本&#xff1a;暂且理解为“超级的文本”&…

安装importlib_resources库的方法最终解答!_Python库

安装Python库importlib_resources 我的环境&#xff1a;Window10&#xff0c;Python3.7&#xff0c;Anaconda3&#xff0c;Pycharm2023.1.3 importlib_resources importlib_resources是一个用于访问Python包中非代码资源&#xff08;如文本、图片等&#xff09;的库&#xff…

界面组件Telerik UI for WPF 2024 Q1新版亮点 - 全新DateRangePicker组件

Telerik UI for WPF拥有超过100个控件来创建美观、高性能的桌面应用程序&#xff0c;同时还能快速构建企业级办公WPF应用程序。UI for WPF支持MVVM、触摸等&#xff0c;创建的应用程序可靠且结构良好&#xff0c;非常容易维护&#xff0c;其直观的API将无缝地集成Visual Studio…

深入剖析Tomcat(三) 实现一个简易连接器

Tomcat中的servlet容器叫做Catalina&#xff0c;Catalina有两个主要模块&#xff1a;连接器与容器。在本章&#xff0c;将会建立一个连接器来增强第二章中应用程序的功能&#xff0c;用一种更好的方式来创建request与response对象。 截止文章编写日期&#xff0c;servlet规范已…

智能设备订购如何使药品供应链受益

自从 Covid-19 大流行扰乱全球供应链以来&#xff0c;制药行业对增强弹性的需求变得比以往任何时候都更加重要。药品供应链已经开始数字化转型&#xff0c;采用新技术有助于确保药品和关键物资按时到达目的地并支持长期业务战略。其中一种解决方案是在移动设备上进行智能设备订…

微信小程序开发笔记

微信小程序开发笔记 1 微信小程序的项目结构 2 页面组成 一个微信小程序是由一个或多个页面组成的&#xff0c;这些页面被存放在pages目录中。下面以pages 目录下的index页面为例展示其组成部分&#xff0c;index页面的组成部分如下图所示。 由上图可知&#xff0c;index页面…

Linux 磁盘管理和文件系统

硬盘的物理结构&#xff1a; 盘片硬盘有多个盘片&#xff0c;每盘片2面磁头每面一个磁头 硬盘的数据结构&#xff1a; 扇区盘片被分为多个扇形区域&#xff0c;扇区:每个扇区存放512字节的数据&#xff0c;硬盘的最小存储单位磁道同一盘片不同半径的同心圆&#xff0c;是由磁…

【Python系列】非异步方法调用异步方法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

️️️Vue3+Element-Plus二次封装一个可定制化的table组件

前言 为什么需要二次封装 开发后台管理系统,会接触到很多表格和表单,一但表格表单多起来,仅仅只需要一小部分改变&#xff0c;都需要在中重写一大堆代码,许多重复逻辑,我们可以把重复逻辑抽离出来二次封装一个组件 使用,减少在开发中需要编写的代码。 为什么需要定制化 每个…