STL -萃取特性迭代器
1. STL简单概述
a. STL六大组成部分
- 容器(Container)
- 空间配置器(allocator)
- 算法(Algorithm)
- 迭代器(Iterator)
- 仿函数(Function object)
- 适配器(Adaptor)
b. STL六大组件内在联系
-
空间分配器为容器分配内存空间。
注意:无论是为什么类型分配内存,分配器都 只是分配内存,而不执行构造函数
-
算法 只关心具体的做法,而不关心是什么 容器 。所以需要 迭代器 作为 容器 与 算法 的桥梁,将两者连接起来。
-
算法 中会常常搭配 仿函数 来更好的完成其工作
-
适配器 将一个class 的接口转换为另一个 class 的接口,使原本因接口不兼容而不能合作的 class,可以一起运作。
-
容器 所使用的 迭代器,其相当一部分操作是在 容器 内实现的。
2. 组件部分详细信息
a. 内存配置器
-
容器使用配置器来进行内存空间的分配、释放,其相关头文件为
stl_alloc.h等。空间分配器有如下两种,这两种分配方式各有各的好坏。
- 第一级分配器
__malloc_alloc_template,即时分配即时释放, - 第二级分配器
__default_alloc_template,小型内存池。
- 第一级分配器
-
容器中通过调用配置器的静态函数来 分配、释放 内存,而配置器则在底层调用
malloc和free来满足用户需求。
b. 迭代器
-
迭代器的本质就是"指针",只不过这个指针有点特别,它比较智能。
-
算法通过迭代器来对容器进行操作,使算法不必了解容器本身的结构。
-
迭代器探幽
-
迭代器的相关实现 (源码位于
stl_iterator.h和stl_iterator_base.h)COPYtemplate <class _Category, class _Tp, class _Distance = ptrdiff_t,class _Pointer = _Tp *, class _Reference = _Tp &>struct iterator {typedef _Category iterator_category; // 迭代器的种类typedef _Tp value_type; // 迭代器所指对象的类型typedef _Distance difference_type; // 两两迭代器之间,距离的类型typedef _Pointer pointer; // 迭代器所指对象的指针typedef _Reference reference; // 迭代器所指对象的引用 }; -
迭代器又细分为以下几种类型
COPY// 迭代器的tag。对应类型的迭代器中,其iterator_category就是对应的tag struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag {}; struct bidirectional_iterator_tag : public forward_iterator_tag {}; struct random_access_iterator_tag : public bidirectional_iterator_tag {};// 输入迭代器 template <class _Tp, class _Distance> struct input_iterator {typedef input_iterator_tag iterator_category;typedef _Tp value_type;typedef _Distance difference_type;typedef _Tp* pointer;typedef _Tp& reference; }; // 输出迭代器 struct output_iterator {typedef output_iterator_tag iterator_category;typedef void value_type;typedef void difference_type;typedef void pointer;typedef void reference; }; // 正向迭代器 template <class _Tp, class _Distance> struct forward_iterator {typedef forward_iterator_tag iterator_category;typedef _Tp value_type;typedef _Distance difference_type;typedef _Tp* pointer;typedef _Tp& reference; };// 双向迭代器 template <class _Tp, class _Distance> struct bidirectional_iterator {typedef bidirectional_iterator_tag iterator_category;typedef _Tp value_type;typedef _Distance difference_type;typedef _Tp* pointer;typedef _Tp& reference; }; // 随机访问迭代器 template <class _Tp, class _Distance> struct random_access_iterator {typedef random_access_iterator_tag iterator_category;typedef _Tp value_type;typedef _Distance difference_type;typedef _Tp* pointer;typedef _Tp& reference; }; -
迭代器中的
iterator_category和value_type等等,它们只是类型名。那么迭代器是如何将这些信息返回给调用者呢?
实际上,SGI STL灵活的使用了模板参数推导的特性来完成这些任务,例如如下代码COPY// iterator_category template <class _Tp, class _Distance> inline input_iterator_tag iterator_category(const input_iterator<_Tp, _Distance>&) {return input_iterator_tag(); }inline output_iterator_tag iterator_category(const output_iterator&) {return output_iterator_tag(); } #define __ITERATOR_CATEGORY(__i) iterator_category(__i) // value_type template <class _Tp, class _Distance> inline _Tp* value_type(const bidirectional_iterator<_Tp, _Distance>&) {return (_Tp*)(0); }template <class _Tp, class _Distance> inline _Tp* value_type(const random_access_iterator<_Tp, _Distance>&) {return (_Tp*)(0); } #define __VALUE_TYPE(__i) value_type(__i)当不同类型的指针使用宏定义
__VALUE_TYPE时,由于模板参数推导的特点,程序会调用参数类型相匹配的函数。既然参数类型匹配,那么返回的也一定是匹配的类型。 -
Traits技术(重中之重)-
iterator_traits-
iterator_traits 技术用于萃取出iterator的对应类型,例如
value_type、iterator_category等等。
iterator本身便可以使用对应宏定义(例如__VALUE_TYPE)来取出对应类型。但原生指针并没有这些方法,所以需要套一层iterator_traits,让iterator_traits“帮助”原生指针,将所需的相关信息返回给调用者。 -
iterator_traits相关源码COPYtemplate <class _Iterator> struct iterator_traits { typedef typename _Iterator::iterator_category iterator_category; typedef typename _Iterator::value_type value_type; typedef typename _Iterator::difference_type difference_type; typedef typename _Iterator::pointer pointer; typedef typename _Iterator::reference reference; };template <class _Tp> struct iterator_traits<_Tp*> { typedef random_access_iterator_tag iterator_category; typedef _Tp value_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef _Tp& reference; };可以看到,
iterator_traits对待iterator和原生指针的方式,是不一样的。
-
-
type_traits-
iterator_traits技术只能用来规范迭代器,对于迭代器之外的东西没有加以规范。所以type_traits就应运而生。 -
iterator_traits是萃取迭代器的特性,而__type_traits是萃取型别的特性。
__type_traits有如下几个类型has_trivial_default_constructor—— 是否使用默认构造函数has_trivial_copy_constructor—— 是否使用默认拷贝构造函数has_trivial_assignment_operator—— 是否使用默认赋值运算符has_trivial_destructor—— 是否使用默认析构函数is_POD_type—— 是否是POD类型
返回的是__true_type或__false_type结构
-
其相关源码如下
COPYstruct __true_type {}; struct __false_type {};template <class _Tp> struct __type_traits {typedef __true_type this_dummy_member_must_be_first;/* Do not remove this member. It informs a compiler whichautomatically specializes __type_traits that this__type_traits template is special. It just makes sure thatthings work if an implementation is using a templatecalled __type_traits for something unrelated. *//* The following restrictions should be observed for the sake ofcompilers which automatically produce type specific specializationsof this class:- You may reorder the members below if you wish- You may remove any of the members below if you wish- You must not rename members without making the correspondingname change in the compiler- Members you add will be treated like regular members unlessyou add the appropriate support in the compiler. */typedef __false_type has_trivial_default_constructor;typedef __false_type has_trivial_copy_constructor;typedef __false_type has_trivial_assignment_operator;typedef __false_type has_trivial_destructor;typedef __false_type is_POD_type; };__STL_TEMPLATE_NULL struct __type_traits<int> {typedef __true_type has_trivial_default_constructor;typedef __true_type has_trivial_copy_constructor;typedef __true_type has_trivial_assignment_operator;typedef __true_type has_trivial_destructor;typedef __true_type is_POD_type; };
-
-
-
应用
-
为什么迭代器要分这么多的类型呢?原因是为了实现STL速度与效率的提高。
根据迭代器的类型,算法可以对该种类的迭代器使用效率最高的操作方式。
例如,如果对char*类型的iterator执行copy操作,那么copy函数就可以直接使用memcpy来完成操作,而不是遍历复制再构造。如此以提高算法的效率。
请看如下源码:COPYvector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x) {/* .... */__STL_TRY{// 当vector的成员函数调用 uninitialized_copy 时,程序会根据迭代器类型执行特定的 uninitialized_copy操作__new_finish = uninitialized_copy(_M_start, __position, __new_start);construct(__new_finish, __x);++__new_finish;__new_finish = uninitialized_copy(__position, _M_finish, __new_finish);} __STL_UNWIND((destroy(__new_start, __new_finish),_M_deallocate(__new_start, __len)));/* .... */ }// 如果是char*类型的迭代器就直接调用memmove。如果不是,则调用使用迭代器的uninitialized_copy函数 template <class _InputIter, class _ForwardIter> inline _ForwardIter uninitialized_copy(_InputIter __first, _InputIter __last,_ForwardIter __result) {return __uninitialized_copy(__first, __last, __result,// 注意到这里获取了迭代器所指向对象的类型__VALUE_TYPE(__result)); }// 如果迭代器是一个指向某个对象的指针,则调用内含_Tp*类型参数的__uninitialized_copy template <class _InputIter, class _ForwardIter, class _Tp> inline _ForwardIter __uninitialized_copy(_InputIter __first, _InputIter __last,_ForwardIter __result, _Tp*) {// 注意这里获取了迭代器所指对象的is_POD信息typedef typename __type_traits<_Tp>::is_POD_type _Is_POD;return __uninitialized_copy_aux(__first, __last, __result, _Is_POD()); }// 如果这个对象类型是POD的,直接copy以提高效率 template <class _InputIter, class _ForwardIter>` inline _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,_ForwardIter __result,__true_type) {return copy(__first, __last, __result); } // 否则,只能一个个的遍历并执行构造函数 template <class _InputIter, class _ForwardIter> _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,_ForwardIter __result,__false_type) {_ForwardIter __cur = __result;__STL_TRY {for ( ; __first != __last; ++__first, ++__cur)_Construct(&*__cur, *__first);return __cur;}__STL_UNWIND(_Destroy(__result, __cur)); }
-
-
c. 容器
- vector
- vector的本质就是一个空间连续数组。与普通数组不同的是,该数组"可长可短"。
- vector的核心成员是三个迭代器,分别为
_Tp* _M_start—— 指向所分配数组的起始位置_Tp* _M_finish—— 指向已使用空间的末端位置+1_Tp* _M_end_of_storage—— 指向所分配数组的末尾位置+1
- list
- list是一个头尾相连的双向环状链表,由一个个节点头尾相连所构成。
- 其关键的成员只有一个,
_List_node<_Tp>* _M_node—— 指向链表的末尾节点,该节点的成员_M_next指向的是链表的起始节点。
相关文章:
STL -萃取特性迭代器
1. STL简单概述 a. STL六大组成部分 容器(Container)空间配置器(allocator)算法(Algorithm)迭代器(Iterator)仿函数(Function object)适配器(Ad…...
python pandas写入csv
在Python的Pandas库中,可以使用to_csv方法将DataFrame对象写入CSV文件。以下是一个简单的示例: import pandas as pd# 创建一个DataFrame对象 data {Name: [Alice, Bob, Charlie, David],Age: [25, 30, 35, 40],City: [New York, Los Angeles, Chicago…...
oracle 数据库建集群式数据库的DBLINK的语法
根据需要修改以下红色字体的部分即可。 1、连接集群式数据库DBLINK语法 create public database link 自定义的dblink名字 connect to 连接对方数据库的用户名 identified by "密码" using (DESCRIPTION (ADDRESS_LIST (FAILOVER ON) (LOAD_BALANCE OFF) …...
基于JAVA的毕业设计分配选题系统 开源项目
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 专业档案模块2.2 学生选题模块2.3 教师放题模块2.4 选题审核模块 三、系统展示四、核心代码4.1 查询专业4.2 新增专业4.3 选择课题4.4 取消选择课题4.5 审核课题 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpri…...
Android 接入指纹识别
接入指纹框架:https://github.com/Tencent/soter implementation com.github.Tencent.soter:soter-wrapper:2.0.91.Application中初始化 class IApplication : Application() {override fun onCreate() {super.onCreate()instance thisinitSort()}private fun in…...
如何通过代理IP安全使用Linkedln领英?
LinkedIn是跨境外贸必备的拓客工具,世界各地的许多专业人士都使用领英来作为发布和共享内容的主要工具,这使得它成为跨境出海必备的渠道工具。 但是不少做外贸的朋友都知道,领英账号很容易遭遇限制封禁,但如果善用工具࿰…...
嵌入式驱动学习第一周——定时器与延时函数
前言 这篇博客一起学习定时器,定时器是最常用到的功能之一,其最大的作用之一就是提供了延时函数。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏&…...
Tips杂记
🥲 🥸 🤌 🫀 🫁 🥷 🐻❄️🦤 🪶 🦭 🪲 🪳 🪰 🪱 🪴 🫐 🫒 🫑…...
可以用numpy为for加速
Numpy除了用于科学计算,还有一个功能是可以代替某些for循环,进行同样的功能实现,有于是向量矩阵运算,碰到复杂的for时,计算速度可以提高,从而提高程序性能。以下是一些常用的NumPy函数和操作,可…...
cartographer ceres后端优化
这里引用一篇文章 https://zhuanlan.zhihu.com/p/567635409 因为cartographer中的代码有的地方添加了AddParameterBlock,有的地方没有添加,会引起歧义,原来AddParameterBlock可以隐式添加优化变量,这篇文章介绍了具体原因,核心内容如下: AddParameterBlock的作用作用一:…...
day57 集合 List Set Map
List实现类 List接口特点:元素有序 可重复 Arraylist 可变数组 jdk 8 以前Arraylist容量初始值10 jdk8 之后初始值为0,添加数据时,容量为10; ArrayList与Vector的区别? LinkList:双向链表 优点࿱…...
蓝桥杯:真题讲解3(C++版)附带解析
报纸页数 来自:2016年七届省赛大学C组真题(共8道题) 分析: --画出报纸长的样子,如果我们在上面多画一张报纸,那么就符合题意的5,6,11,12。 观察这张图:观察3…...
继续预训练对大语言模型的影响
翻译自文章:Investigating Continual Pretraining in Large Language Models: Insights and Implications 摘要 本文研究了大型语言模型(LLMs)中不断学习(CL)的不断发展领域,重点是制定有效和可持续的训练…...
关于空频变换的知识点
1.DCT变换: 离散余弦变换是一种将图像从空域转换到频域的技术,它可以将图像分解为频域分量。对于RGB图像,它由红色(R)、绿色(G)和蓝色(B)三个通道组成。当应用DCT变换时…...
纯css实现-让字符串在文字少时显示为居中对齐,而在文字多时显示为左对齐
纯css实现-让字符串在文字少时显示为居中对齐,而在文字多时显示为左对齐 使用flex实现 思路 容器样式(.container): Flex容器的BFC性质使得其内部的子元素(.text-box)在水平方向上能够居中,通过justify-c…...
初学HTMLCSS——盒子模型
盒子模型 盒子:页面中所有的元素(标签),都可以看做是一个 盒子,由盒子将页面中的元素包含在一个矩形区域内,通过盒子的视角更方便的进行页面布局盒子模型组成:内容区域(content&…...
吸猫毛空气净化器哪个好?推荐除猫毛好的宠物空气净化器品牌
如今,越来越多的家庭选择养宠物!虽然家里变得更加温馨,但养宠可能会带来异味和空气中的毛发增多可能会引发健康问题,这也是一个大问题。 但我不想家里到处都是异味,尤其是便便的味道,所以很需要一款能够处…...
【玩转408数据结构】线性表——双链表、循环链表和静态链表(线性表的链式表示 下)
知识回顾 在前面的学习中,我们已经了解到了链表(线性表的链式存储)的一些基本特点,并且深入的研究探讨了单链表的一些特性,我们知道,单链表在实现插入删除上,是要比顺序表方便的,但是…...
分布式概念
分布式概念 一、分布式介绍1.1 分布式计算1.1.1 分布式计算的方法1.1.1 分布式计算与互联网的普及1.1.2 分布式计算项目1.1.3 参与计算 1.2 分布式存储系统1.2.1 P2P 数据存储系统1.2.2 云存储系统 1.3 应用 二、分布式基础概念2.1 微服务2.2 集群2.3 分布式2.4 节点2.5 远程调…...
vue中的ref/reactive区别及原理
Vue中的ref和reactive是两种不同的数据响应式管理方式。 ref是Vue 3中新加入的特性,它可以将一个普通的JavaScript对象转换为响应式对象。通过ref创建的响应式对象在访问和修改时会自动触发重新渲染。ref返回的是一个包含value属性的对象,访问或修改数据…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
