12. STL的原理

news2025/4/3 6:11:25

目录

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(双向)。

按功能从弱到强排列如下:

  1.     输入迭代器(Input Iterator)
  2.     输出迭代器(Output Iterator)
  3.     前向迭代器(Forward Iterator)
  4.     双向迭代器(Bidirectional Iterator)
  5.     随机访问迭代器(Random Access Iterator)

        比如说 sort 使用的就是随机迭代器, list 就不能调用它,因为 list 使用的是双向迭代器。

迭代器失效

        迭代器失效是指一个原本指向容器元素的迭代器在容器被修改后,可能变得无效。使用失效的迭代器会导致程序运行错误甚至崩溃。

对于 std::vector 来说,以下操作可能导致迭代器失效:

  1. 内存重新分配:

    • 扩容时,底层存储数据的内存地址会重新分配。
    • 所有现有的迭代器、指针和引用都会失效
  2. 元素插入或删除
    • 插入或删除可能会导致部分迭代器失效,尤其是插入删除位置的迭代器

        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
  1. rbegin() 的实现

    • 内部实际上存储的是 end() 迭代器

    • 但解引用时返回的是 end()-1 位置的元素

  2. rend() 的实现

    • 内部实际上存储的是 begin() 迭代器

    • 解引用时会试图访问 begin()-1(这是未定义行为)

  3. 对称性

    • 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. 组件化设计(架构优势)

        六大组件通过迭代器解耦,扩展性强且维护成本低。

  1. 空间配置器给容器提供统一的内存分配和释放接口
  2. 适配器作用于容器,通过封装现有组件并提供新的接口来满足不同的需求(stack、queue)
  3. 适配器作用于迭代器,通过封装现有组件并提供新的接口来满足不同的需求(反向迭代器)
  4. 容器提供了迭代器接口(begin、end)
  5. 迭代器用来实现了算法,算法脱离具体的存储结构
  6. 算法通过统一简单的方式:迭代器,操作各种底层不同容器
  7. 迭代器作为算法和容器之间的桥梁存在
  8. 仿函数给容器提供了元素组织方式(默认建大堆→建小堆)
  9. 仿函数给算法提供了更灵活的机制(sort默认排升序→排降序)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OSPFv3 的 LSA 详解

一、复习&#xff1a; OSPFv3 运行于 IPv6 协议上&#xff0c;所以是基于链路&#xff0c;而不是基于网段&#xff0c;它实现了拓扑和网络的分离。另外&#xff0c;支持一个链路上多个进程&#xff1b;支持泛洪范围标记和泛洪不识别的报文&#xff08;ospfv2 的行为是丢弃&…

python 原型链污染学习

复现SU的时候遇到一道python原型链污染的题&#xff0c;借此机会学一下参考&#xff1a; 【原型链污染】Python与Jshttps://blog.abdulrah33m.com/prototype-pollution-in-python/pydash原型链污染 文章目录 基础知识对父类的污染命令执行对子类的污染pydash原型链污染打污染的…

入栈操作-出栈操作

入栈操作 其 入栈操作 汇编代码流程解析如下&#xff1a; 出栈操作 其 出栈操作 汇编代码流程解析如下&#xff1a;

C++ 多态:面向对象编程的核心概念(一)

文章目录 引言1. 多态的概念2. 多态的定义和实现2.1 实现多态的条件2.2 虚函数2.3 虚函数的重写/覆盖2.4 虚函数重写的一些其他问题2.5 override 和 final 关键字2.6 重载/重写/隐藏的对比 3. 纯虚函数和抽象类 引言 多态是面向对象编程的三大特性之一&#xff08;封装、继承、…

Python数据可视化-第3章-图表辅助元素的定制

教材 本书为《Python数据可视化》一书的配套内容&#xff0c;本章为第3章-图表辅助元素的定制 本章主要介绍了图表辅助元素的定制&#xff0c;包括认识常用的辅助元素、设置坐标轴的标签、设置刻度范围和刻度标签、添加标题和图例、显示网格、添加参考线和参考区域、添加注释文…

springboot实现异步导入Excel的注意点

springboot实现异步导入Excel 需求前言异步导入面临的问题实现异步如何导入大Excel文件避免OOM&#xff1f;异步操作后&#xff0c;如何通知导入结果&#xff1f;如何加快导入效率&#xff1f;将导入结果通知给用户后&#xff0c;如何避免重复通知&#xff1f; 优化点完结撒花&…

Linux练习——有关硬盘、联网、软件包的管理

1、将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为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 的文章&#xff0c;是关于真实世界去模糊任务的数据集构建的工作&#xff0c;论文作者来自韩国首尔大学 Abstract 要训练去模糊网络&#xff0c;拥有一个包含成对模糊图像和清晰图像的合适数据集至关重要。现有的数据集收集模糊图像的方式主要有两…

Cocos Creator Shader入门实战(七):RGB不同算法效果的实现,及渲染技术、宏定义、属性参数的延伸配置

引擎&#xff1a;3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 上篇文章&#xff0c;讲解了Cocos Shader如何通过setProperty动态设置材质的属性&#xff0c;以及设置属性时候的一些注意事项&#xff0c;比如&#xff1a; 一、CCEffect部分properties参数的设定后&…

算法学习记录:递归

递归算法的关键在于回复现场&#xff0c;dfs&#xff08;&#xff09;函数返回值、结束条件、它的作用。 目录 1.综合练习 2. 二叉树的深搜 1.综合练习 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 关键在画出的决策树当中&#xff0c;前面使用过的2、3&#xff0c;…

可发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 开发板为例&#xff0c;配置以太网外设 这里有一点需要注意原理图 RMII_TXD0…

Flutter_学习记录_AppBar中取消leading的占位展示

将leading设置为null将automaticallyImplyLeading设置为false 看看automaticallyImplyLeading的说明&#xff1a; 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…

未来派几何风格包装徽标品牌海报标牌logo设计无衬线英文字体安装包 Myfonts – Trakya Sans Font Family

Trakya Sans 是一种具有几何风格的现代无衬线字体。Futura、Avant Garde 等。它具有现代条纹&#xff0c;这是宽度和高度协调的结果&#xff0c;尤其是在小写字母中&#xff0c;以支持易读性。 非常适合广告和包装、编辑和出版、徽标、品牌和创意产业、海报和广告牌、小文本、寻…

C语言深度解析:从零到系统级开发的完整指南

一、C语言的核心特性与优势 1. 高效性与直接硬件控制 C语言通过编译为机器码的特性&#xff0c;成为系统级开发的首选语言。例如&#xff0c;Linux内核通过C语言直接操作内存和硬件寄存器&#xff0c;实现高效进程调度。 关键点&#xff1a; malloc/free直接管理内存&#…

ctfshow WEB web8

首先确定注入点&#xff0c;输入以下payload使SQL恒成立 ?id-1/**/or/**/true 再输入一下payload 使SQL恒不成立 ?id-1/**/or/**/false 由于SQL恒不成立, 数据库查询不到任何数据, 从而导致页面空显示 由以上返回结果可知&#xff0c;该页面存在SQL注入&#xff0c;注入点…

【Linux】U-Boot 加载并启动 Linux 系统程序

U-Boot 加载并启动 Linux 系统程序 零、介绍 最近在玩一些嵌入式的开发板&#xff0c;在引导操作系统时需要用到U-Boot&#xff0c;故此研究一下。 U-Boot&#xff08;Universal Bootloader&#xff09;是一款开源的通用引导加载程序&#xff0c;专为嵌入式系统设计&#xff…

jarvisoj API调用 [JSON格式变XXE]

http://web.jarvisoj.com:9882/ 题目要求&#xff1a;请设法获得目标机器 /home/ctf/flag.txt 中的flag值 抓包得到&#xff1a; POST /api/v1.0/try HTTP/1.1 Host: web.jarvisoj.com:9882 Content-Length: 36 Accept-Language: zh-CN,zh;q0.9 User-Agent: Mozilla/5.0 (W…

机器学习的一百个概念(4)下采样

前言 本文隶属于专栏《机器学习的一百个概念》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见[《机器学习的一百个概念》 ima 知识库 知识库广场搜索&…