STL—容器—list【list的介绍和基本使用】【list的迭代器失效问题】
STL—容器—list
list的使用并不难,有了之前使用string和vector的基础后,学习起来并不难。因此这里不在详细的讲解如何使用,而是大致的将其基本接口都熟悉一下
1.list介绍
list的文档介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。其实就是双向循环链表
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素。

2.list的使用
ist中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,从而达到可扩展的能力。以下为list中一些常见的重要接口
2.1list的构造

list (size_type n, const value_type& val = value_type()),构造n个值val的元素的listlist(),构造空的listlist (const list& x),拷贝构造list (InputIterator first, InputIterator last),迭代器构造
四个构造函数的使用代码:
void test1()
{// list (size_type n, const value_type& val = value_t)list<int> l1(5, 1);list<int>::iterator it1 = l1.begin();while (it1 != l1.end()){cout << *it1 << " ";++it1;}cout << endl;//list (const list& x)list<int> l2(l1);list<int>::iterator it2 = l2.begin();while (it2 != l2.end()){cout << *it2 << " ";++it2;}cout << endl;//list()list<int> l3;l3.push_back(2);l3.push_back(3);l3.push_back(4);list<int>::iterator it3 = l3.begin();while (it3 != l3.end()){cout << *it3 << " ";it3++;}cout << endl;// list(InputIterator first, InputIterator last)list<int> l4(l3.begin(), l3.end());list<int>::iterator it4 = l4.begin();while (it4 != l4.end()){cout << *it4 << " ";it4++;}cout << endl;}
2.2 list 迭代器的使用
list是一个双向迭代器,因为其结构是双向链表,如果是list_forword就是单向迭代器。vector是随机迭代器——支持begin + n的操作,可以随机访问。
正向迭代器,反向迭代器,带const的正向迭代器,带const的反向迭代器
正向迭代器用begin()和end(),反向的用rbegin() 和 rend()

【注意】
-
begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
-
rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
使用代码如下:
// 带const迭代器的使用
void print_list(const list<int>& l)
{list<int>::const_iterator cit = l.begin();while (cit != l.end()){cout << *cit << " ";cit++;}cout << endl;
}// 带const的反向迭代器的使用
void print_reverse_list(const list<int>& l)
{list<int>::const_reverse_iterator rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;
}// 迭代器的使用
void test2()
{list<int> l;l.push_back(1);l.push_back(1);l.push_back(1);l.push_back(1);l.push_front(0);l.push_front(-1);l.pop_back();l.pop_back();list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << " ";it++;}cout << endl;print_list(l);list<int>::reverse_iterator rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";rit++;}cout << endl;print_reverse_list(l);}
要注意:
只要支持迭代器的容器就支持范围for循环、
// 范围for循环,只要支持迭代器的容器就支持范围for循环、
void test4()
{list<string> ls;ls.push_back("aaa");ls.push_back("bbb");ls.push_back("ccc");for (auto e : ls){cout << e << " ";}cout << endl;
}
2.3赋值运算符的使用
这个就和之前的赋值运算符一样用就行,比较简单。
// 赋值运算符
void test3()
{list<int> l1;l1.push_back(1);l1.push_back(2);list<int> l2;l2 = l1;print_list(l2);
}
2.4 list capacity()

在list容器中,不太存在容量这个接口,因为不会有提前开辟的空间等待使用,没什么意义,而是用多少开多少。
empty和size接口的使用
// empty 和 size接口的使用
void test1()
{list<int> l;l.push_back(1);if (l.empty()){cout << "该list为空\n";cout << l.size() << endl;}else{cout << "该list不为空\n";cout << l.size() << endl;}
}
2.5 list element access

front和back的使用:
// front 和 back的使用
void test2()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);cout << l.front() << endl; // 1cout << l.back() << endl; // 4
}
2.6list modifiers(增删查改)
这里只展示了部分的接口

使用代码如下:
// 增删查改类接口使用
void test3()
{list<int> l;// push_backl.push_back(3);l.push_back(4);print_list(l); // 3 4// push_frontl.push_front(2);l.push_front(1);print_list(l); // 1 2 3 4// pop_back / pop_frontl.pop_back(); l.pop_front();print_list(l); // 2 3// insertl.insert(l.begin(), 0);l.insert(l.end(), 4);l.insert(++l.begin(), 1);auto pos = ++l.begin();l.insert(pos, 1);print_list(l); // 0 1 1 2 3 4// erasel.erase(l.begin());l.erase(--l.end());pos = l.begin();l.erase(pos);print_list(l); // 1 2 3// swaplist<int> l2;l2.push_back(1);l2.push_back(1);l2.push_back(1);l.swap(l2);cout << "l: ";print_list(l); // l: 1 1 1cout << "l2:";print_list(l2); // l2: 1 2 3// clearl2.clear(); // 虽然有效元素被清空了,但是并不意味着l2为空if (l2.empty()){cout << "l2不为空\n";print_list(l2);}else{cout << "l2为空\n";}
}// findlist<int>::iterator posn = find(l.begin(), l.end(), 3); // find没找到返回l.end()的位置if (posn != l.end()){l.insert(posn, 30); // 在list下这里的posn不会失效,但是vector下就会失效了。}print_list(l);
在使用接口的时候,如果遇到不会的,可以查阅文档
3.list的迭代器失效问题
在讲述list的迭代器失效问题,我们先来看一个例子:
void print_list(const list<int>& l)
{list<int>::const_iterator cit = l.begin();while (cit != l.end()){cout << *cit << " ";++cit;}cout << endl;
}void print_vector(const vector<int>& v)
{vector<int>::const_iterator cit = v.begin();while (cit != v.end()){cout << *cit << " ";++cit;}cout << endl;
}void test1()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);list<int>::iterator pos1 = find(l.begin(), l.end(), 3);if(pos1 != l.end()){l.insert(pos1, 30);// insert完成后,pos迭代器不会失效。因为他是list结构,vector就会直接崩溃l.erase(pos1);}print_list(l);vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator pos2 = find(v.begin(), v.end(), 3);if (pos2 != v.end()){v.insert(pos2, 30); // insert之后的pos2迭代器失效了。//v.erase(pos2); // vs里直接报错}print_vector(v);
}
在这段代码中,list中使用insert插入数据后的pos1不会在成为失效的迭代器,这是因为list是双向链表的结构,链表的数据是放在一个个结点中的,因此pos1指向的数据不会被移动,也不会改变。

而vector中就会让pos2成为失效的迭代器,**原因是:**1.不增容会导致pos2指向的数据出现错误。2.增容
了会直接导致pos2成为野指针。因为v的地址变动了。具体可以复习vector。STL—容器—vector-CSDN博客这篇博客中有讲述vector的两种迭代器失效的情况。

经过上面的例子分析,我们发现list特殊的双向链表结构导致vector中出现的这种迭代器失效的情况不会在list中出现。
但是list还是存在着迭代器失效的情况。
下面我们就来看看这个情况,在学习vector的时候说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
来看一段代码:
// list的迭代器失效问题
void test2()
{// 只有删除节点的时候会失效int arr[] = { 1,2,3,4,5,6,7,8,9,10 };list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));list<int>::iterator it = l.begin();while (it != l.end()){l.erase(it);// 此时的it已经是无效了。因为所指向的节点已经被删除了++it; }print_list(l);
}
正确代码:
void test2()
{// 只有删除节点的时候会失效int arr[] = { 1,2,3,4,5,6,7,8,9,10 };list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));list<int>::iterator it = l.begin();while (it != l.end()){l.erase(it++); // 或者是it = l.erase(it);}print_list(l);
}
总结:
list在oj的使用频率没有vector出现的频率那么高,因此这边我们只是简单的使用list的基本接口就足够了,重点是在list的模拟实现上。
相关文章:
STL—容器—list【list的介绍和基本使用】【list的迭代器失效问题】
STL—容器—list list的使用并不难,有了之前使用string和vector的基础后,学习起来并不难。因此这里不在详细的讲解如何使用,而是大致的将其基本接口都熟悉一下 1.list介绍 list的文档介绍 list是可以在常数范围内在任意位置进行插入和删除…...
【面试宝典】MySQL 面试问题
一、MySQL 中有哪几种锁? MySQL中的锁机制是数据库并发控制的重要组成部分,它用于管理多个用户对数据库资源的访问,确保数据的一致性和完整性。MySQL中的锁可以根据不同的分类标准进行分类,以下是一些常见的分类方式及对应的锁类…...
【Cpp筑基】三、对象和类
【Cpp筑基】三、对象和类 Cpp系列笔记目录 【Cpp筑基】一、内联函数、引用变量、函数重载、函数模板 【Cpp筑基】二、声明 vs 定义、头文件、存储持续性作用域和链接性、名称空间 【Cpp筑基】三、对象和类 【Cpp筑基】四、重载运算符、友元、类的转换函数 【Cpp筑基】五、类的继…...
数据库原理面试-核心概念-问题理解
目录 1.数据库、数据库系统与数据库管理系统 2.理解数据独立性 3.数据模型 4.模式、外模式和内模式 5.关系和关系数据库 6.主键与外键 7.SQL语言 8.索引与视图 9.数据库安全 10.数据库完整性 11.数据依赖和函数依赖 12.范式?三范式?为什么要遵…...
【JavaScript】JavaScript里的“先斩后奏”之王 shift()方法
定义: JavaScript中 shift 方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组! 解释: 成语解释: 先斩后奏是一个汉语成语,其拼音为xiān zhǎn hu zu。这个成语最早出自于汉班固的《汉书申屠嘉传》,原指先把罪犯处决,再向皇帝奏闻。在现代…...
Python面试宝典第32题:课程表
题目 你这个学期必须选修numCourses门课程,记为0到numCourses - 1。在选修某些课程之前,需要一些先修课程。先修课程按数组prerequisites给出,其中prerequisites[i] [ai, bi],表示如果要学习课程ai,则必须先学习课程b…...
简单介绍BTC的Layer2项目RGB
这里写自定义目录标题 介绍(历史背景,项目成员)核心技术组成部分一次性密封条(single-use-seals)客户端验证(client-side validation) 总结 注:该内容不构成投资建议,有些…...
跨境电商卖家必看:搭建安全稳定测评自养号环境系统
对于卖家而言,测评作为一种低成本、高回报的推广策略,对于提升产品流量、转化率、优化关键词质量分及增强链接权重等方面均发挥着积极作用。以下是自养号优势及测评环境搭建技术要点 一、搭建安全稳定的测评环境系统 核心要点: 硬件参数去…...
如何对open62541.h/open62541.c的UA_Client进行状态(在线/掉线)监控
文章目录 背景解决方案注意事项 背景 目前在利用open62541.h/open62541.c编写了一个与PLC进行OPCUA通讯的上位机程序。 上位机这边会定时对PLC的某个opcua变量进行写操作。但是假如PLC离线或者说拔掉网线,上位机就会直接崩溃死机,并且报如下的错误&…...
高等数学 第九讲 一元函数积分学的应用
1. 一元函数积分学的应用 文章目录 1. 一元函数积分学的应用1. 几何应用1.1 用定积分表达和计算平面图形的面积1.2 用定积分表达和计算旋转体的体积1.2.1 微分法1.2.2 二重积分法1.2.3 古尔丁定理1.2.4 旋转体的体积公式总结 1.3 用定积分表达和计算函数的平均数1.4 其他几何应…...
django如何更新数据库字段并与数据库保持同步?
关键步骤: 第一步: 执行:python manage.py makemigrations 你的项目名称第二步:它会提示你选1还是2,这里因为添加字段,所以选1第三步:出现>>>这个,直接输入这个第四步&am…...
jenkins插件 SSH Publishers
Jenkins 是一个开源的自动化服务器,常用于持续集成和持续交付 (CI/CD)。以下是一些与 Jenkins 相关的 SSH 发布者及其功能: SSH 插件: 功能: 允许 Jenkins 通过 SSH 执行远程命令。用户可以配置 SSH 服务器,使用 SSH 密钥进行身份…...
Kafka Client客户端操作详解
文章目录 基础客户端版本消息生产者消息消费者踩坑 客户端属性分析消费者分组消费机制生产者拦截器消息序列化消息分区路由机制生产者消息缓存机制发送应答机制生产者消息幂等性生产者消息事务 客户端流程总结 基础客户端版本 导入依赖 <properties><project.build.…...
【HarmonyOS NEXT星河版开发学习】小型测试案例15-博客列表
个人主页→VON 收录专栏→鸿蒙开发小型案例总结 基础语法部分会发布于github 和 gitee上面(暂未发布) 前言 该案例主要是ForEach渲染的练习,ForEach可以基于数组的个数,渲染组件个数(简化代码) 在…...
go-zero中统一返回前端数据格式的几种方式
方式一、直接定义一个成功和失败的方法,在代码里面修改(对代码有侵入,每次都要修改代码) 1、封装一个统一返回的方法 package utilsimport ("github.com/zeromicro/go-zero/rest/httpx""net/http" )type Body struct {Code int json:"code…...
【向量数据库】Ubuntu编译安装FAISS
参考官方的安装指导:https://github.com/facebookresearch/faiss/blob/main/INSTALL.md,不需要安装的可以跳过 ~$ wget https://github.com/facebookresearch/faiss/archive/refs/tags/v1.8.0.tar.gz ~$ tar -zxvf v1.8.0.tar.gz ~$ cd faiss-1.8.0 ~$ …...
制造知识普及(九)--企业内部物料编码(IPN)与制造商物料编码(MPN)
在日常的物料管理业务逻辑中,一物一码是物料管理的基本的业务规则,不管物料从产品开发还是仓库管理,甚至成本核算,都要遵循这个原则,才能保证产品数据的准确性,才具备唯一追溯的可行性。大部分企业都是这种…...
【整数规划】+【0—1规划】解决优化类问题(Matlab代码)
目录 文章目录 前言 一、整数规划 分类: 二、典例讲解 1.背包问题 2.指派问题 总结 前言 如果觉得本篇文章还不错的话,给作者点个赞鼓励一下吧😁😁😁 在规划问题中,有些最优解可能是分数或小数&am…...
Linux下如何使用Curl进行网络请求
在Linux系统上,Curl是一个非常强大的网络请求工具,可以用于发送各种类型的HTTP请求,并获取响应结果。它支持常见的HTTP方法,如GET、POST、PUT、DELETE等,还支持HTTPS、FTP等不同协议。Curl提供了丰富的参数选项&#x…...
PostgreSQL 触发器
PostgreSQL 触发器 PostgreSQL触发器是一种强大的数据库对象,它可以在特定的数据库事件发生时自动执行预定义的操作。这些事件可以是插入、更新或删除表中的行。触发器通常用于强制复杂的业务规则、提供审计跟踪、数据同步以及实现复杂的约束。 触发器的基本概念 …...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
