侯捷 C++ STL标准库和泛型编程 —— 4 分配器 + 5 迭代器

4 分配器

4.1 测试

分配器都是与容器共同使用的,一般分配器参数用默认值即可

list<string, allocator<string>> c1;

不建议直接用分配器分配空间,因为其需要在释放内存时也要指明大小

int* p; 	
p = allocator<int>().allocate(512, (int*)0); // 临时变量调用函数
allocator<int>().deallocate(p,512); // 释放时需要指明之前申请的大小

4.2 源码解析

VC6下:allocator 中有 allocatedeallocate 其分别用函数 ::operator new::operator delete 来调用 c 中的 mallocfree

pointer allocate(size_type _N, const void*){...} // 后面一个参数只是用来指明类型的
void deallocate(void _FARQ *_P, size_type){...}

这里经过包装还是调用的 malloc 和 free,其执行效率变慢;且如果申请的空间比较小,会有较大比例的额外开销(cookie,调试模式所需空间等等)

GCC2.9 下:其容器都是调用的名叫 alloc 的分配器

在这里插入图片描述

其从0到15有一共16个链表,分别代表8字节到16*8字节,例如 #0 的位置用 malloc 要一大块内存,然后做切割,切成一块一块的8字节空间不带cookie,用单向链表穿起来;当要申请6字节的大小的空间时,其就会到 #0 中占用一块 —— 节省空间

在 GCC4.9 中各个容器又用回了 allocator,而上面的 alloc 变成了__poll_alloc

5 迭代器

5.1 迭代器的设计准则

Iterator 必须提供5种 associated type(说明自己的特性的)来供算法来识别,以便算法正确地使用 Iterator

template <class T, class Ref, class Ptr>
struct __list_iterator
{...typedef bidirectional_iterator_tag iterator_category; // (1)迭代器类别:双向迭代器	typedef T value_type; // (2)迭代器所指对象的类型typedef Ptr pointer; // (3)迭代器所指对象的指针类型typedef Ref reference; // (4)迭代器所指对象的引用类型typedef ptrdiff_t difference_type; // (5)两个迭代器之间的距离类型// iter1-iter2 时,要保证数据类型以存储任何两个迭代器对象间的距离...}
// 迭代器回答// | Λ
// | |
// | | 
// V |// 算法直接提问
template <typename I>
inline void algorithm(I first, I last)
{...I::iterator_categoryI::pointerI::referenceI::value_typeI::difference_type...
}

但当 Iterator 并不是 class 时,例如指针本身,就不能 typedef 了 —— 这时就要设计一个 Iterator Traits

Traits:用于定义类型特征的信息,从而在编译时根据类型的不同进行不同的操作或处理 —— 类似一个萃取机(针对不同类型做不同操作:偏特化)

image-20230827102754004
// I是class iterator进
template <class I>
struct Iterator_traits
{typedef typename I::iterator_category iterator_category;typedef typename I::value_type value_type;typedef typename I::difference_type difference_type;typedef typename I::pointer pointer;typedef typename I::reference reference;// typename用于告诉编译器,接下来的标识符是一个类型名,而不是一个变量名或其他名称// I::iterator_category 是一个类型名// iterator_category是这个迭代器类型内部的一个嵌套类型(typedef ...)
};// I是指向T的指针进
template <class T>
struct Iterator_traits<T*>
{typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef ptrdiff_t difference_type;typedef T* pointer;typedef T& reference;
};// I是指向T的常量指针进
template <class T>
struct Iterator_traits<const T*>
{typedef random_access_iterator_tag iterator_category;typedef T value_type; // 注意是T而不是const T// 按理说是const T,但声明一个不能被赋值的变量无用// 所以value_type不应加上consttypedef ptrdiff_t difference_type;typedef const T* pointer;typedef const T& reference;
};

除了 Iterator Traits,还有很多其他 Traits

5.2 迭代器的分类

迭代器的分类对算法的效率有很大的影响

  1. 输入迭代器 input_iterator_tag:istream迭代器
  2. 输出迭代器 output_iterator_tag:ostream迭代器
  3. 单向迭代器 forward_iterator_tag:forward_list,hash类容器
  4. 双向迭代器 bidirectional_iterator_tag: list、红黑树容器
  5. 随机存取迭代器 random_access_iterator_tag:array、vector、deque
image-20230831085955167

用有继承关系的class实现:

  1. 方便迭代器类型作为参数进行传递,如果是整数的是不方便的
  2. 有些算法的实现没有实现所有类型的迭代器类别,就要用继承关系去找父迭代器类别
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 {};

算法 distance 将会按照迭代器的类别进行不同的操作以提升效率

  • 如果迭代器可以跳,直接 last - first 即可
  • 如果迭代器不能跳,就只能一步一步走来计数

两者的效率差别很大

image-20230902091354849

但如果迭代器类别是 farward_iterator_tag 或者 bidirectional_iterator_tag,该算法没有针对这种类型迭代器实现,就可以用继承关系来使用父类的实现(继承关系——“is a” 子类是一种父类,当然可以用父类的实现)

算法 copy 将经过很多判断筛选来找到最高效率的实现

其中用到了 Iterator TraitsType Traits 来进行筛选

has trivial op=() 是指的有不重要的拷贝赋值函数(例如复数用的自带的拷贝赋值函数)

image-20230902093014515

注意:由于 output_iterator_tag(例如 ostream_iterator)是 write-only,无法用 * 来读取内容,所以在设计时就需要再写个专属版本

在源码中,算法都是模板函数,接受所有的 iterator,但一些算法只能用特定的 iterator,所以其会在模板参数的名称上进行暗示:

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

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

相关文章

nodejs+vue交通违章查询及缴费elementui

第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性&#xff1a;技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性&#xff1a; 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…

【STM32】IAP升级03关闭总中断,检测栈顶指针

IAP升级方法 IAP升级时需要关闭总中断 TM32在使用时有时需要禁用全局中断&#xff0c;比如MCU在升级过程中需禁用外部中断&#xff0c;防止升级过程中外部中断触发导致升级失败。 ARM MDK中提供了如下两个接口来禁用和开启总中断&#xff1a; __disable_irq(); // 关闭总中…

8. 基于消影点进行相机内参(主点)的标定

目录 1. ocam模型2. 消影点3. 基于消影点进行相机主点标定3.1 基于ocam模型的主点标定 感谢大家的阅读。 1. ocam模型 可以参考我的另一篇博客ocam模型。 这里简单提一下ocam模型&#xff1a; 这个模型将中心折反射相机和鱼眼相机统一在一个通用模型下&#xff0c;也称为泰勒模…

如何解决版本不兼容Jar包冲突问题

如何解决版本不兼容Jar包冲突问题 引言 “老婆”和“妈妈”同时掉进水里&#xff0c;先救谁&#xff1f; 常言道&#xff1a;编码五分钟&#xff0c;解冲突两小时。作为Java开发来说&#xff0c;第一眼见到ClassNotFoundException、 NoSuchMethodException这些异常来说&…

VUE3照本宣科——应用实例API与setup

VUE3照本宣科——应用实例API与setup 前言一、应用实例API1.createApp()2.app.use()3.app.mount() 二、setup 前言 &#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f33e;&#x1f4dd;记录学习成果&#xff0c;以便温故而知新 “VUE3照本宣科”是指照着中文官网和菜鸟教…

Multiple CORS header ‘Access-Control-Allow-Origin‘ not allowed

今天在修改天天生鲜超市项目的时候&#xff0c;因为使用了前后端分离模式&#xff0c;前端通过网关统一转发请求到后端服务&#xff0c;但是第一次使用就遇到了问题&#xff0c;比如跨域问题&#xff1a; 但是&#xff0c;其实网关里是有配置跨域的&#xff0c;只是忘了把前端项…

JavaSE | 初识Java(七) | 数组 (下)

Java 中提供了 java.util.Arrays 包 , 其中包含了一些操作数组的常用方法 代码实例&#xff1a; import java.util.Arrays int[] arr {1,2,3,4,5,6}; String newArr Arrays.toString(arr); System.out.println(newArr); // 执行结果 [1, 2, 3, 4, 5, 6] 数组拷贝 代码实例…

VRRP配置案例(路由走向分析,端口切换)

以下配置图为例 PC1的配置 acsw下行为access口&#xff0c;上行为trunk口&#xff0c; 将g0/0/3划分到vlan100中 <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sysname acsw [acsw] Sep 11 2023 18:15:48-08:00 acsw DS/4/DATASYNC_CFGCHANGE:O…

Python 无废话-基础知识元组Tuple详讲

“元组 Tuple”是一个有序、不可变的序列集合&#xff0c;元组的元素可以包含任意类型的数据&#xff0c;如整数、浮点数、字符串等&#xff0c;用()表示&#xff0c;如下示例&#xff1a; 元组特征 1) 元组中的各个元素&#xff0c;可以具有不相同的数据类型&#xff0c;如 T…

python使用mitmproxy和mitmdump抓包在手机上抓包(三)

现在手机的使用率远超过电脑&#xff0c;所以这篇记录用mitmproxy抓手机包&#xff0c;实现手机流量监控。 环境&#xff1a;win10 64位&#xff0c;Python 3.10.4&#xff0c;雷电模拟器4.0.78&#xff0c;android版本7.1.2&#xff08;设置-拉至最底部-关于平板电脑&#xf…

Grander因果检验(格兰杰)原理+操作+解释

笔记来源&#xff1a; 1.【传送门】 2.【传送门】 前沿原理介绍 Grander因果检验是一种分析时间序列数据因果关系的方法。 基本思想在于&#xff0c;在控制Y的滞后项 (过去值) 的情况下&#xff0c;如果X的滞后项仍然有助于解释Y的当期值的变动&#xff0c;则认为 X对 Y产生…

IDEA2023 常用配置(JDK/系统设置等常用配置)

目录 一、JDK及编译目录设置 1 项目的JDK设置 2 out目录和编译版本 二、相关详细设置 1 打开详细配置界面 1、显示工具栏 2、默认启动项目配置 3、取消自动更新 2 设置整体主题 1、选择主题 2、设置菜单和窗口字体和大小 3、设置IDEA背景图 3 设置编辑器主题样式…

Office 2021 小型企业版商用办公软件评测:提升工作效率与协作能力的专业利器

作为一名软件评测人员&#xff0c;我将为您带来一篇关于 Office 2021 小型企业版商用办公软件的评测文章。在这篇评测中&#xff0c;我将从实用性、使用场景、优点和缺点等多个方面对该软件进行客观分析&#xff0c;在专业角度为您揭示它的真正实力和潜力。 一、实用性&#xf…

家用无线路由器如何用网线桥接解决有些房间无线信号覆盖不好的问题(低成本)

环境 光猫ZXHN F6600U 水星MW325R 无线百兆路由器 100M宽带&#xff0c;2.4G无线网络 苹果手机 安卓平板电脑 三室一厅94平 问题描述 家用无线路由器如何用网线桥接解决有些房间无线信号不好问题低成本解决&#xff0c;无线覆盖和漫游 主路由器用的运营商的光猫自带无…

Gorsonpy的计算器

Gorsonpy的计算器 0.页面及功能展示1. PSP表格2.解题思路描述3.设计实现过程4.程序性能改进5.异常处理6.单元测试展示7.心路历程和收获 这个作业属于哪个课程https://bbs.csdn.net/forums/ssynkqtd-05这个作业要求在哪里https://bbs.csdn.net/topics/617294583这个作业的目标完…

docker基础学习

1. 安装docker #安装 yum 源 docker wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo #安装 docker 此处安装的是18版本的&#xff0c;还有19,20等等更高版本 yum -y install docker-ce-18.06.1.ce-3.el7 #…

《XSS-Labs》01. Level 1~10

XSS-Labs 索引Level-1题解 Level-2题解 Level-3题解总结 Level-4题解 Level-5题解总结 Level-6题解 Level-7题解 Level-8题解 Level-9题解 Level-10题解 靶场部署在 VMware - Win7。 靶场地址&#xff1a;https://github.com/do0dl3/xss-labs 只要手动注入恶意 JavaScript 脚本…

一文拿捏基于redis的分布式锁、lua、分布式性能提升

1.分布式锁 jdk的锁&#xff1a; 1、显示锁&#xff1a;Lock 2、隐式锁&#xff1a;synchronized 使用jdk锁保证线程的安全性要求&#xff1a;要求多个线程必须运行在同一个jvm中 但现在的系统基本都是分布式部署的&#xff0c;一个应用会被部署到多台服务器上&#xff0c;s…

数学建模Matlab之检验与相关性分析

只要做C题基本上都会用到相关性分析、一般性检验等&#xff01; 回归模型性能检验 下面讲一下回归模型的性能评估指标&#xff0c;用来衡量模型预测的准确性。下面是每个指标的简单解释以及它们的应用情境&#xff1a; 1. MAPE (平均绝对百分比误差) 描述: 衡量模型预测的相对…

UG\NX二次开发 用程序修改“用户默认设置”

文章作者:里海 来源网站:《里海NX二次开发3000例专栏》 简介 可以用程序修改“用户默认设置”吗?下面是用代码修改“用户默认设置->基本环境->用户界面->操作记录->操作记录语言”的例子。 效果 代码 #include <uf_defs.h> #include <NXOpen/NXExcept…