12. STL的原理
目录
1. 容器、迭代器、算法
什么是迭代器?
迭代器的作用?
迭代器的类型?
迭代器失效
迭代器的实现细节:
2. 适配器
什么是适配器?
适配器种类:
3. 仿函数
什么是仿函数?
仿函数与算法和容器的关系:
4.空间配置器
5.STL的优缺点是什么?设计的好的地方和不好的地方?
STL包含六大组件,这些组件是杂糅到一起的,互相之间有关联。
问到就详细讲容器和迭代器。
1. 容器、迭代器、算法
上一篇讲了容器,这里主要介绍它和其他组件的关系
| 组件 | 与容器的关系 | 典型协作场景 |
|---|---|---|
| 迭代器 | 容器提供迭代器接口 begin()、end() | 算法通过迭代器访问容器内容 |
| 算法 | 通过迭代器操作容器 | sort(), find()等算法处理容器数据 |
| 仿函数 | 定义容器排序/比较规则 | set的比较函数 |
| 适配器 | 基于容器构建特殊接口 | stack基于deque实现 |
| 分配器 | 控制容器内存管理 | 自定义内存分配策略 |
-
算法通过迭代器操作容器
-
同一算法可作用于不同容器
-
不同算法对迭代器类别有不同要求:
-
sort需要随机访问迭代器(不能用于list) -
find只需要输入迭代器(可用于所有容器)
-
什么是迭代器?
迭代器的设计非常的天才,它充分体现面向对象的封装特性,容器的底层各不相同(哈希、树、数组等),容器内部是私有的,外部访问不了他们的内部结构,使用迭代器封装,在不需要暴露底层复杂结构的同时,还提供了统一、简单的方式访问容器,也就是它提供了一种统一的方法来访问容器中的元素,而不需要了解容器的内部结构。
迭代器的作用?
迭代器把容器和算法连接了起来,作为算法和容器之间的桥梁,算法通过迭代器直接访问各种容器,如果不符合算法要求又可以直接报错。比如sort算法,在设计时设计的是需要给他传一个随机迭代器,如果给他一个其他类型的迭代器则会报错。
算法的具体实现,直接脱离了具体的存储结构,也就是各种容器,直接通过迭代器来实现,依赖各种迭代器的类型,体现了设计角度的复用,使得同一算法可应用于任何满足迭代器要求的容器。
指针本身就是随机访问迭代器,使得传统数组也能参与算法:
int arr[10] = {...};
std::sort(arr, arr + 10);
迭代器的类型?
在C++标准库中,不同容器支持不同类型的迭代器:
- std::list:使用双向迭代器,支持前向和后向遍历。
- std::vector 和 std::deque、std::string:使用随机访问迭代器,支持任意位置的访问和高效的算术运算。
- std::forward_list:使用前向迭代器,仅支持单向遍历。
- std::set, std::map, std::multiset, std::multimap:使用双向迭代器。
- std::unordered_set, std::unordered_map, std::unordered_multiset, std::unordered_multimap:使用前向迭代器。
层级低的容器不能访问层级高的算法。层级高的容器可以访问层级低的函数。比如:vector和string就可以调用reverse(双向)。
按功能从弱到强排列如下:
- 输入迭代器(Input Iterator)
- 输出迭代器(Output Iterator)
- 前向迭代器(Forward Iterator)
- 双向迭代器(Bidirectional Iterator)
- 随机访问迭代器(Random Access Iterator)
比如说 sort 使用的就是随机迭代器, list 就不能调用它,因为 list 使用的是双向迭代器。
迭代器失效
迭代器失效是指一个原本指向容器元素的迭代器,在容器被修改后,可能变得无效。使用失效的迭代器会导致程序运行错误甚至崩溃。
对于 std::vector 来说,以下操作可能导致迭代器失效:
-
内存重新分配:
- 扩容时,底层存储数据的内存地址会重新分配。
- 所有现有的迭代器、指针和引用都会失效
- 元素插入或删除
- 插入或删除可能会导致部分迭代器失效,尤其是插入删除位置的迭代器
vector扩容,也就是说vector底层旧空间被释放掉,而在打印时,it还使用的是释放前的旧空间,在对it进行操作时,实际操作的是一块已经被释放的空间,从而引起崩溃。
erase删除某位置的元素后,pos位置之后的元素会向前搬移,没有导致底层空间的改变,理论上迭代器应该不会失效,但是如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效。
其他:
string下的失效,与vector类似,string在插入+扩容操作+erase后,迭代器也会失效,不能再访问。erase函数执行后,it所指向的节点已经被删除,因此it无效,在下一次使用it时,必须先给其赋值。也就是用迭代器接受一下erase的返回值。
list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在被删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
迭代器的实现细节:
08.vector-CSDN博客
2. 适配器
什么是适配器?
适配器是一种结构型设计模式,它将一个类的接口转换成客户所期望的另一个接口。在STL中,适配器主要作用于容器和迭代器,通过封装现有组件并提供新的接口来满足不同的需求 。
主要和容器有关,也可能和迭代器有关,比如说反向迭代器就是一个适配器,适配器体现的是封装复用。所以可以分为容器适配器和迭代器适配器。
适配器种类:
容器适配器:10.stack 和 queue_queue 与stack-CSDN博客
迭代器适配器(以反向迭代器为例):10.stack 和 queue_queue 与stack-CSDN博客
正向序列: [A][B][C][D][E]↑ ↑ ↑ ↑ ↑ ↑
正向迭代器:begin end反向序列: [E][D][C][B][A]↑ ↑ ↑ ↑ ↑ ↑
反向迭代器:rbegin rend
对应正向: end begin
-
rbegin()的实现:-
内部实际上存储的是
end()迭代器 -
但解引用时返回的是
end()-1位置的元素
-
-
rend()的实现:-
内部实际上存储的是
begin()迭代器 -
解引用时会试图访问
begin()-1(这是未定义行为)
-
-
对称性:
-
rbegin().base() == end() -
rend().base() == begin()
-
3. 仿函数
什么是仿函数?
仿函数(Functor),也称为函数对象,是C++中一种特殊的类。它通过重载operator()操作符,使得该类的对象可以像普通函数一样被调用。
针对算法可以实现各种功能,最经典的就是比大小,特点就是可以控制规则
仿函数与算法和容器的关系:
算法通过仿函数参数实现灵活的行为控制:
// 排序算法使用仿函数定义比较规则
sort(vec.begin(), vec.end(), greater<int>());
某些容器依赖仿函数定义元素的组织方式:
// set使用less仿函数默认升序排列
std::set<int, std::less<int>> ascendingSet;// priority_queue使用greater仿函数实现小顶堆
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
C++11后,lambda表达式成为创建仿函数的便捷方式:
sort(v.begin(), v.end(), [](auto& a, auto& b) {return a.value < b.value;
});
4.空间配置器
空间配置器是STL中负责内存管理的核心组件,它为容器提供统一的内存分配和释放接口。
主要职责是:
-
内存的分配与释放
-
对象的构造与析构
-
提供标准化的内存管理接口
所有STL容器都使用空间配置器管理内存,默认使用std::allocator:
template <class T, class Allocator = std::allocator<T>>
class vector;template <class T, class Allocator = std::allocator<T>>
class list;
其他功能:
-
解耦内存策略:将内存管理与容器实现分离
-
灵活扩展:允许自定义内存管理策略(如内存池、共享内存等)
5.STL的优缺点是什么?设计的好的地方和不好的地方?
STL缺点:
- 不支持线程安全(注意容器不是线程安全的)
- 没有持续更新,增加新容器(跳表。。。)
- 有一些冗余设计,如array,forward_list 等
STL优点:
1. 泛型编程(核心优势)
STL通过模板实现了类型无关的通用数据结构和算法,一套代码可处理任意数据类型,极大提高了代码复用率。
2. 高性能(核心竞争力)
采用编译时多态(模板)替代运行时多态(虚函数),算法经过深度优化(如sort用内省排序),内存管理可定制(如内存池),效率接近手写C代码。
3. 组件化设计(架构优势)
六大组件通过迭代器解耦,扩展性强且维护成本低。

- 空间配置器给容器提供统一的内存分配和释放接口
- 适配器作用于容器,通过封装现有组件并提供新的接口来满足不同的需求(stack、queue)
- 适配器作用于迭代器,通过封装现有组件并提供新的接口来满足不同的需求(反向迭代器)
- 容器提供了迭代器接口(begin、end)
- 迭代器用来实现了算法,算法脱离具体的存储结构
- 算法通过统一简单的方式:迭代器,操作各种底层不同容器
- 迭代器作为算法和容器之间的桥梁存在
- 仿函数给容器提供了元素组织方式(默认建大堆→建小堆)
- 仿函数给算法提供了更灵活的机制(sort默认排升序→排降序)
相关文章:
12. STL的原理
目录 1. 容器、迭代器、算法 什么是迭代器? 迭代器的作用? 迭代器的类型? 迭代器失效 迭代器的实现细节: 2. 适配器 什么是适配器? 适配器种类: 3. 仿函数 什么是仿函数? 仿函数与算法和容器的…...
OSPFv3 的 LSA 详解
一、复习: OSPFv3 运行于 IPv6 协议上,所以是基于链路,而不是基于网段,它实现了拓扑和网络的分离。另外,支持一个链路上多个进程;支持泛洪范围标记和泛洪不识别的报文(ospfv2 的行为是丢弃&…...
python 原型链污染学习
复现SU的时候遇到一道python原型链污染的题,借此机会学一下参考: 【原型链污染】Python与Jshttps://blog.abdulrah33m.com/prototype-pollution-in-python/pydash原型链污染 文章目录 基础知识对父类的污染命令执行对子类的污染pydash原型链污染打污染的…...
Windows 图形显示驱动开发-WDDM 2.4功能-GPU 半虚拟化(十一)
注册表设置 GPU虚拟化标志 GpuVirtualizationFlags 注册表项用于设置半虚拟化 GPU 的行为。 密钥位于: DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\GpuVirtualizationFlags 定义了以下位: 位描述0x1 为所有硬件适配器强制设置…...
入栈操作-出栈操作
入栈操作 其 入栈操作 汇编代码流程解析如下: 出栈操作 其 出栈操作 汇编代码流程解析如下:...
C++ 多态:面向对象编程的核心概念(一)
文章目录 引言1. 多态的概念2. 多态的定义和实现2.1 实现多态的条件2.2 虚函数2.3 虚函数的重写/覆盖2.4 虚函数重写的一些其他问题2.5 override 和 final 关键字2.6 重载/重写/隐藏的对比 3. 纯虚函数和抽象类 引言 多态是面向对象编程的三大特性之一(封装、继承、…...
传统策略梯度方法的弊端与PPO的改进:稳定性与样本效率的提升
为什么传统策略梯度方法(如REINFORCE算法)在训练过程中存在不稳定性和样本效率低下的问题 1. 传统策略梯度方法的基本公式 传统策略梯度方法的目标是最大化累积奖励的期望值。具体来说,优化目标可以表示为: max θ J ( θ )…...
我的机器学习学习之路
学习python的初衷 • hi,今天给朋友们分享一下我是怎么从0基础开始学习机器学习的。 • 我是2023年9月开始下定决心要学python的,目的有两个,一是为了提升自己的技能和价值,二是将所学的知识应用到工作中去,提升工作…...
Spring Boot 的自动装配
Spring Boot 的自动装配(Auto Configuration)是其核心特性之一,通过智能化的条件判断和配置加载机制,极大简化了传统 Spring 应用的配置复杂度。其原理和实现过程可概括为以下几个关键点: 一、核心触发机制:…...
Python数据可视化-第3章-图表辅助元素的定制
教材 本书为《Python数据可视化》一书的配套内容,本章为第3章-图表辅助元素的定制 本章主要介绍了图表辅助元素的定制,包括认识常用的辅助元素、设置坐标轴的标签、设置刻度范围和刻度标签、添加标题和图例、显示网格、添加参考线和参考区域、添加注释文…...
`git commit --amend` 详解:修改提交记录的正确方式
文章目录 git commit --amend 详解:修改提交记录的正确方式1. 修改提交信息2. 补充遗漏的文件3. 结合 --amend 进行交互式修改4. 已推送提交的修改总结 git commit --amend 详解:修改提交记录的正确方式 git commit --amend 用于修改最近一次的提交&…...
Linux系统下C语言fork函数使用案例
一、fork函数的作用 生成一个子进程,异步执行某个任务; 二、子进程的作用 1、子进程能复制一份父进程的变量、函数; 2、子进程可以和父进程同时并发执行; 函数语法: pid_t fork() 说明:调用后返回一个进程…...
springboot实现异步导入Excel的注意点
springboot实现异步导入Excel 需求前言异步导入面临的问题实现异步如何导入大Excel文件避免OOM?异步操作后,如何通知导入结果?如何加快导入效率?将导入结果通知给用户后,如何避免重复通知? 优化点完结撒花&…...
Linux练习——有关硬盘、联网、软件包的管理
1、将你的虚拟机的网卡模式设置为nat模式,给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 #使用nmtui打开文本图形界面配置网络 [rootrhcsa0306 ~]# nmtui #使用命令激活名为 ens160 的 NetworkManager 网络连接 [rootrhcsa0306 ~]# nmcli c up ens160 #通…...
论文阅读:GS-Blur: A 3D Scene-Based Dataset for Realistic Image Deblurring
今天介绍一篇 2024 NeurIPS 的文章,是关于真实世界去模糊任务的数据集构建的工作,论文作者来自韩国首尔大学 Abstract 要训练去模糊网络,拥有一个包含成对模糊图像和清晰图像的合适数据集至关重要。现有的数据集收集模糊图像的方式主要有两…...
经典动态规划问题:爬楼梯的多种解法详解
引言 今天我们要解决一个经典的算法问题——爬楼梯问题。这个问题看似简单,但蕴含了多种解法,从递归到动态规划,再到组合数学,每种方法都有其独特的思路和优化方式。本文将详细讲解四种解法,并通过代码和图解帮助大家…...
Kubernetes深度解析:云原生时代的容器编排引擎
一、背景与演进 1. 容器革命的必然产物 Kubernetes(K8s)诞生于2014年,是Google基于其内部Borg系统的开源实现。在传统单体应用向微服务架构转型的浪潮中,容器技术(如Docker)解决了应用打包和环境隔离问题…...
Cocos Creator Shader入门实战(七):RGB不同算法效果的实现,及渲染技术、宏定义、属性参数的延伸配置
引擎:3.8.5 您好,我是鹤九日! 回顾 上篇文章,讲解了Cocos Shader如何通过setProperty动态设置材质的属性,以及设置属性时候的一些注意事项,比如: 一、CCEffect部分properties参数的设定后&…...
leetcode102 二叉树的层次遍历 递归
(1) 找出重复的子问题。 层次遍历是每一层的节点从左到右的遍历,所以在遍历的时候我们可以先遍历左子树,再遍历右子树。 需要注意的是,在遍历左子树或者右子树的时候,涉及到向上或者向下遍历,为了让递归的过程中的同…...
Netty源码—10.Netty工具之时间轮二
大纲 1.什么是时间轮 2.HashedWheelTimer是什么 3.HashedWheelTimer的使用 4.HashedWheelTimer的运行流程 5.HashedWheelTimer的核心字段 6.HashedWheelTimer的构造方法 7.HashedWheelTimer添加任务和执行任务 8.HashedWheelTimer的完整源码 9.HashedWheelTimer的总结…...
算法学习记录:递归
递归算法的关键在于回复现场,dfs()函数返回值、结束条件、它的作用。 目录 1.综合练习 2. 二叉树的深搜 1.综合练习 39. 组合总和 - 力扣(LeetCode) 关键在画出的决策树当中,前面使用过的2、3,…...
启山智软实现b2c单商户商城对比传统单商户的优势在哪里?
启山智软实现 B2C 单商户商城具有以下对比优势: 技术架构方面 先进的框架选型:基于 SpringCloud 等主流框架开发,是百万真实用户沉淀并检验的商城系统,技术成熟稳定,能应对高并发场景,保证系统在大流量访…...
可发1区的超级创新思路(python\matlab实现):MPTS+Lconv+注意力集成机制的Transformer时间序列模型
首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 应用场景 该模型主要用于时间序列数据预测问题,包含功率预测、电池寿命预测、电机故障检测等等。 一、模型整体架构(本文以光伏功率预测为例) 本模型由多尺度特征提取模块(MPTS)…...
三、分类模块,通用组件顶部导航栏Navbar
1.封装通用组件顶部导航栏Navbar 不同效果 Component export struct MkNavbar {Prop title: string Prop leftIcon: ResourceStr $r("app.media.ic_public_left")ProprightIcon: ResourceStr $r("app.media.ic_public_more")PropshowLeftIcon: boolean…...
PHY——LAN8720A 寄存器读写 (二)
文章目录 PHY——LAN8720A 寄存器读写 (二)工程配置引脚初始化代码以太网初始化代码PHY 接口实现LAN8720 接口实现PHY 接口测试 PHY——LAN8720A 寄存器读写 (二) 工程配置 这里以野火电子的 F429 开发板为例,配置以太网外设 这里有一点需要注意原理图 RMII_TXD0…...
Flutter_学习记录_AppBar中取消leading的占位展示
将leading设置为null将automaticallyImplyLeading设置为false 看看automaticallyImplyLeading的说明: Controls whether we should try to imply the leading widget if null. If true and [AppBar.leading] is null, automatically try to deduce what the leading…...
PHP泛型与集合的未来:从动态类型到强类型的演进
文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…...
未来派几何风格包装徽标品牌海报标牌logo设计无衬线英文字体安装包 Myfonts – Trakya Sans Font Family
Trakya Sans 是一种具有几何风格的现代无衬线字体。Futura、Avant Garde 等。它具有现代条纹,这是宽度和高度协调的结果,尤其是在小写字母中,以支持易读性。 非常适合广告和包装、编辑和出版、徽标、品牌和创意产业、海报和广告牌、小文本、寻…...
C语言深度解析:从零到系统级开发的完整指南
一、C语言的核心特性与优势 1. 高效性与直接硬件控制 C语言通过编译为机器码的特性,成为系统级开发的首选语言。例如,Linux内核通过C语言直接操作内存和硬件寄存器,实现高效进程调度。 关键点: malloc/free直接管理内存&#…...
ctfshow WEB web8
首先确定注入点,输入以下payload使SQL恒成立 ?id-1/**/or/**/true 再输入一下payload 使SQL恒不成立 ?id-1/**/or/**/false 由于SQL恒不成立, 数据库查询不到任何数据, 从而导致页面空显示 由以上返回结果可知,该页面存在SQL注入,注入点…...
