Effective STL 1.仔细选择你的容器

news/2024/11/28 19:35:59/

Effective STL 1.仔细选择你的容器

文章目录

  • Effective STL 1.仔细选择你的容器
    • 迭代器
    • 容器
      • 分类
      • 连续内存容器和基于节点的容器的区别
    • 如何选择容器
    • 结语
      • >>>>> 欢迎关注公众号【三戒纪元】 <<<<<

  • 标准序列容器

vector、string、deque 和 list

  • 标准关联容器

    set、multiset、map 和 multimap

迭代器

  1. 输入迭代器

    每个迭代位置只能被读1次的只读迭代器,通常表现为 istream_iterator

  2. 输出迭代器

    每个迭代位置只能被写1次的只写迭代器,通常表现为 ostream_iterator

  3. 前向迭代器

    有输入和输出迭代器的能力,可以反复读写1个位置,不支持 operator--,可以高效地向前移动任意次数

    散列容器的一种设计可以产生前向迭代器;

    单链表容器也提供前向迭代器

  4. 双向迭代器

    像前向迭代器一样,后退很容易。标准关联容器都提供双向迭代器,list也有

  5. 随机访问迭代器

    可以做双向迭代器一样的事情,但也提供“迭代器算术”,即迭代器有一步向前或向后跳的能力。

    vector、string 和 deque 都提供随机访问迭代器。

    指针数组的指针可以作为数组的随机访问迭代器。

容器

STL有迭代器算法函数对象,但对于大多数C++程序员,容器是最突出的。

它们比数组更强大更灵活,可以动态增长(也常是缩减),可以管理属于它们自己的内存,可以跟踪它们拥有的对象数目,可以限制它们支持操作的算法复杂度等等。

分类

类别说明
标准STL序列容器vectorstringdequelist
标准STL关联容器setmultisetmapmultimap
非标准序列容器slist和ropeslist是一个单向链表,rope本质上是一个重型字符串。(“绳子(rope)”是重型的“线(string)”)
非标准关联容器hash_sethash_multisethash_maphash_multimap
vector可以作为string的替代品
vector作为标准关联容器的替代品有时候vector可以在时间和空间上都表现得比标准关联容器好
标准非STL容器包括数组、bitsetvalarraystackqueuepriority_queue
值得注意的是,数组可以和STL算法配合,因为指针可以当作数组的迭代器使用

vectorlistdeque提供给程序员不同的复杂度,因此应该这么用:

  • vector是一种可以默认使用的序列类型
  • 当很频繁地对序列中部进行插入和删除时应该用list
  • 当大部分插入和删除发生在序列的头或尾时可以选择deque这种数据结构

连续内存容器和基于节点的容器的区别

  • 连续内存容器(也叫做基于数组的容器)

    在一个或多个(动态分配)的内存块中保存它们的元素。

    如果一个新元素被查入或者已存元素被删除,其他在同一个内存块的元素就必须向上或者向下移动来为新元素提供空间或者填充原来被删除的元素所占的空间。

    这种移动影响了效率和异常安全。

    标准的连续内存容器是vectorstringdeque

    非标准的rope也是连续内存容器。

  • 基于节点的容器

    在每个内存块(动态分配)中只保存一个元素。

    容器元素的插入或删除只影响指向节点的指针,而不是节点自己的内容。

    所以当有东西插入或删除时,元素值不需要移动。

    表现为链表的容器——比如listslist——是基于节点的,所有的标准关联容器也是(它们的典型实现是平衡树)。

    非标准的散列容器使用不同的基于节点的实现。

如何选择容器

  1. 你需要“可以在容器的任意位置插入一个新元素”的能力吗?

    如果是,你需要序列容器,关联容器做不到。

  2. 你关心元素在容器中的顺序吗?

    如果不,散列容器就是可行的选择。否则,你要避免使用散列容器。

  3. 必须使用标准C++中的容器吗?

    如果是,就可以除去散列容器slistrope

  4. 你需要哪一类迭代器?

    如果必须是随机访问迭代器,在技术上你就只能限于vectordequestring,但你也可能会考虑rope

    如果需要双向迭代器,你就用不了slist 散列容器的一般实现。

  5. 当插入或者删除数据时,是否非常在意容器内现有元素的移动

    如果是,你就必须放弃连续内存容器

  6. 容器中的数据的内存布局需要兼容C吗?

    如果是,你就只能用vector

  7. 查找速度很重要吗?

    如果是,你就应该看看散列容器排序的vector标准的关联容器——大概是这个顺序

  8. 你介意如果容器的底层使用了引用计数吗?

    如果是,你就得避开string,因为很多string的实现是用引用计数

    你也不能用rope,因为权威的rope实现是基于引用计数的

    于是你得重新审核你的string,你可以考虑使用vector<char>

  9. 你需要插入和删除的事务性语义吗?也就是说,你需要有可靠地回退插入和删除的能力吗?

    如果是,你就需要使用基于节点的容器

    如果你需要多元素插入(比如,以范围的方式)的事务性语义,你就应该选择list,因为list是唯一提供多元素插入事务性语义的标准容器

    事务性语义对于有兴趣写异常安全代码的程序员来说非常重要。(事务性语义也可以在连续内存容器上实现,但会有一个性能开销,而且代码不那么直观)

  10. 你要把迭代器、指针和引用的失效次数减到最少吗?

    如果是,你就应该使用基于节点的容器,因为在这些容器上进行插入和删除不会使迭代器、指针和引用失效(除非它们指向你删除的元素)。

    一般来说,在连续内存容器上插入和删除会使所有指向容器的迭代器、指针和引用失效

  11. 你需要具有以下特性的序列容器吗:1) 可以使用随机访问迭代器2) 只要没有删除而且插入只发生在容器结尾,指针和引用的数据就不会失效

    这个一个非常特殊的情况,但如果你遇到这种情况,deque就是你梦想的容器

    有趣的是,当插入只在容器结尾时,deque的迭代器也可能会失效deque是**唯一一个“在迭代器失效时不会使它的指针和引用失效”**的标准STL容器。

结语

当面对容器时,STL给了你很多选项。如果你的视线超越了STL的范围,那就会有更多的选项。在选择一个容器前,要保证考虑了所有你的选项。


>>>>> 欢迎关注公众号【三戒纪元】 <<<<<


http://www.ppmy.cn/news/1078724.html

相关文章

【LeetCode每日一题】——1365.有多少小于当前数字的数字

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 排序 二【题目难度】 简单 三【题目编号】 1365.有多少小于当前数字的数字 四【题目描述】 …

如何一键批量查询全部物流信息?

在日常工作中&#xff0c;快递物流信息的查询是一项常规任务。然而&#xff0c;这个过程往往既耗时又费力&#xff0c;尤其是在面对大量单号的情况下。为了解决这个问题&#xff0c;我们推荐使用固乔快递查询助手&#xff0c;一款能够快速、准确地查询快递物流信息的软件。 首先…

ICCV 2023 | 利用双重聚合的Transformer进行图像超分辨率

导读 本文提出一种同时利用图像空间和通道特征的 Transformer 模型&#xff0c;DAT&#xff08;Dual Aggregation Transformer&#xff09;&#xff0c;用于图像超分辨&#xff08;Super-Resolution&#xff0c;SR&#xff09;任务。DAT 以块间和块内的双重方式&#xff0c;在空…

MATLAB中mod函数转化为C语言

背景 有项目算法使用matlab中mod函数进行运算&#xff0c;这里需要将转化为C语言&#xff0c;从而模拟算法运行&#xff0c;将算法移植到qt。 MATLAB中mod简单介绍 语法 b mod(a,m) 说明 b mod(a,m) 返回 a 除以 m 后的余数&#xff0c;其中 a 是被除数&#xff0c;m 是…

一文讲透 JavaScript 应用的演进历程

在不断发展的软件开发领域中&#xff0c;很少有编程语言像JavaScript一样产生深远的影响。它起初只是一种简单的脚本语言&#xff0c;但如今已成为现代Web的驱动力量&#xff0c;改变了应用构建和体验的方式。本文将带你沿着时间线&#xff0c;穿越JavaScript的演进历程&#x…

Java基础二十二(对集合元素排序比较)

对集合元素排序比较 1. 使用 Comparable 接口实现默认排序 Comparable 是 Java 中的一个接口&#xff0c;用于定义对象之间的排序规则。 实现了 Comparable 接口的类可以比较其对象的大小&#xff08;包装类都实现了该接口&#xff09;&#xff0c;从而可以在集合类&#xf…

Windows环境安装redis-dump

安装msys2-x86_64-20190524.exe http://repo.msys2.org/distrib/x86_64/msys2-x86_64-20190524.exe rubyinstaller-devkit-2.7.1-1-x64.exe安装后会询问是否安装这个文件&#xff0c;因为下载速度慢&#xff0c;提前安装 安装rubyinstaller-devkit-2.7.1-1-x64.exe https://gi…

安卓版yolo-fastest

安卓版本yolofastest效果测试 安卓配置OPENCV4ANDROID&#xff0c;见我的博客一篇文章opencv4dandroid配置 这个不需要使用JNI&#xff0c;十分简单的配置 说真的&#xff0c;其实只调用OPENCV的函数&#xff0c;自己写的代码不多&#xff0c;使用OPENCV4ANDROID和JNI的时间差…