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

news2024/11/25 19:33:42

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_category
    I::pointer
    I::reference
    I::value_type
    I::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不应加上const
	typedef 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.coloradmin.cn/o/1053594.html

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

相关文章

图像处理: ImageKit.NET 3.0.10704 Crack

关于 ImageKit.NET3 100% 原生 .NET 图像处理组件。 ImageKit.NET 可让您快速轻松地向 .NET 应用程序添加图像处理功能。从 TWAIN 扫描仪和数码相机检索图像&#xff1b;加载和保存多种格式的图像文件&#xff1b;对图像应用图像滤镜和变换&#xff1b;在显示屏、平移窗口或缩略…

【大家的项目】通用规则引擎——Rush(一)可以自定义的规则引擎,告别发版,快速配置...

前言 很长一段时间在搞过增长和促销的事情&#xff0c;在实现各种活动和玩法时非常心累。每个新的玩法&#xff0c;都需要填一点代码&#xff0c;每次改动都需要走流水线发一次版&#xff0c;烦躁且痛苦。 对于这种&#xff0c;输入不确定&#xff0c;过程不确定&#xff0c;结…

uni-app:官方文档中的canvas实例剖析

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width: 30…

【python海洋专题三】图像修饰之画布和坐标轴

【python海洋专题三】图像修饰之画布和坐标轴 海洋与大气科学 上期读取nc水深文件&#xff0c;并出图 但是存在一些不完美&#xff0c;本期修饰 本期内容目录 1&#xff1a;改变画布大小 2&#xff1a;改变画布背景色 3&#xff1a;改变画布在显示屏中的显示位置 4&#xf…

建筑能源管理(3)——建筑能源监管

为了全面落实科学发展观&#xff0c;提高建筑能源管理水平&#xff0c;进一步降低能源和水资源消耗、合理利用资源&#xff0c;以政府办公建筑和大型公共建筑的运行节能管理为突破口&#xff0c;建立了既有政府办公建筑和大型公共建筑运行节能监管体系&#xff0c;旨在提高政府…

[python 刷题] 刷题常用函数

[python 刷题] 刷题常用函数 最近直到未来一段时间之内应该都会用 python 刷题了&#xff0c;所以记一下碰到的还蛮好用的方法 按照分区实现&#xff0c;基本上刷一个类型的题&#xff0c;了解一些常用函数&#xff0c;就更新一下 这里假设你对编程语言有一定的了解&#xf…

Python海洋专题七之Cartopy画地形水深图的陆地填充

Python海洋专题七之Cartopy画地形水深图的陆地填充 第一期图 本期&#xff1a; 上期 Cartopy画地形水深图 但是陆地没有填充 如图 本期内容 陆地填充 如图&#xff1a; 详细过程如下 1&#xff1a;陆地填充 land feature.NaturalEarthFeature(‘physical’, ‘land’…

如何在Qt6中引入Network模块

2023年10月1日&#xff0c;周日凌晨 如果用的是CMake find_package(Qt6 COMPONENTS Network REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Network) 但在实际使用中&#xff0c;我发现有以下几点要注意&#xff1a; 1、要把“mytarget”换成项目名称 2、要去掉…

指针巩固习题

1.该程序输出的结果为 #include<stdio.h> int main() {int arr[]{1,2,3,4,5};short *p(short*)arr;//转化类型int i0;for(i0;i<4;i){*(pi)0;//short型指针1跳过两个字节}for(i0;i<5;i){printf("%d",arr[i]);}return 0;} 2.程序的输出结果为 #include&…

oracle-使用PLSQL工具自行修改用户密码

1、使用PLSQL工具&#xff0c;输入用户名和原密码登录&#xff0c;如下图 2、登录后&#xff0c;在会话下拉菜单中找到”Change password..” 3、在跳出的窗口中配置新密码&#xff0c;修改完成后单击”确认”&#xff0c;后退出PLSQL 4、重新打开PLSQL&#xff0c;使用新密码登…

1. windows安装elasticSearch

目录 1. 下载 2. 安装和启动 1. 下载 下载地址&#xff1a;https://elasticsearch.cn/download/ 下载7.8.0版本&#xff1a; 下载后的elasticsearch-7.8.0-windows-x86_64.zip文件放在本地合适的位置。 2. 安装和启动 解压elasticsearch-7.8.0-windows-x86_64.zip文件&…

蜂蜜配送销售商城小程序的作用是什么

蜂蜜是农产品中重要的一个类目&#xff0c;其受众之广市场需求量大&#xff0c;但由于非人人必需品&#xff0c;因此传统线下门店经营也面临着痛点&#xff0c;线上入驻平台也有很多限制难以打造自有品牌&#xff0c;无法管理销售商品及会员、营销等&#xff0c;缺少自营渠道&a…

DirectX12_Windows_GameDevelop_1:向量代数

引言 向量在计算机图形学、碰撞检测和物理模拟中扮演者关键的角色。因此在游戏开发之前我们必须先了解向量。本章研究向量的使用。 一、向量 如果你对数学中的向量不太熟悉&#xff0c;建议阅读《3D数学基础&#xff1a;图形和游戏开发 第2版》&#xff0c;如果你需要某些PD…

敏感性分析一览

敏感性分析 SobolMorrisFourier Amplitude Sensitivity Test (FAST)Random Balance Designs - Fourier Amplitude Sensitivity Test (RBD-FAST)Delta Moment-Independent MeasureDerivative-based Global Sensitivity Measure (DGSM)Fractional Factorial Sensitivity Analysis…

Flutter笔记:滚动之-无限滚动与动态加载的实现(GetX简单状态管理版)

Flutter笔记 无限滚动与动态加载的实现&#xff08;GeX简单状态管理版&#xff09; 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq…

Spring Framework 学习笔记5:事务

Spring Framework 学习笔记5&#xff1a;事务 1.快速入门 1.1.准备工作 这里提供一个示例项目 transaction-demo&#xff0c;这个项目包含 Spring 框架、MyBatis 以及 JUnit。 对应的表结构见 bank.sql。 服务层有一个方法可以用于在不同的账户间进行转账&#xff1a; Se…

云原生Kubernetes:对外服务之 Ingress

目录 一、理论 1.Ingress 2.部署 nginx-ingress-controller(第一种方式) 3.部署 nginx-ingress-controller(第二种方式) 二、实验 1.部署 nginx-ingress-controller(第一种方式) 2.部署 nginx-ingress-controller(第二种方式) 三、问题 1.启动 nginx-ingress-controll…

Python海洋专题五之水深地形图海岸填充

Python海洋专题五之水深地形图海岸填充 海洋与大气科学 上期读取nc水深文件&#xff0c;并出图 但是存在一些不完美&#xff0c;本期修饰 本期内容 障眼法&#xff1a;把大于零的数据填充为陆地的灰色&#xff1b; 把等于零的数据画等深线为陆地和海洋的分界线&#xff01;…

怒刷LeetCode的第21天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;哈希表 方法二&#xff1a;计数器数组 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;分治法 方法二&#xff1a;快速幂 迭代 方法三&#xff1a;快速幂 递归 第三题 题目来源 题目内容 …

JUC第十二讲:JUC锁: 锁核心类AQS详解

JUC第十二讲&#xff1a;JUC锁: 锁核心类AQS详解 本文是JUC第十二讲&#xff0c;JUC锁: 锁核心类AQS详解。AbstractQueuedSynchronizer抽象类是核心&#xff0c;需要重点掌握。它提供了一个基于FIFO队列&#xff0c;可以用于构建锁或者其他相关同步装置的基础框架。 文章目录 J…