Effetive STL | 条款2 : 小心对“容器无关代码”的幻想

news2024/11/24 4:47:45

Effetive STL | 条款2 : 小心对“容器无关代码”的幻想

文章目录

  • Effetive STL | 条款2 : 小心对“容器无关代码”的幻想
    • STL 容器特点
    • 推行自己的容器
      • 容器能力的交集
    • 封装
      • Method1: typedef
      • Method2: class
      • >>>>> 欢迎关注公众号【三戒纪元】 <<<<<

STL 容器特点

STL是建立在泛化之上的

  • 数组泛化为容器,参数化了所包含的对象的类型
  • 函数泛化为算法,参数化了所用的迭代器的类型
  • 指针泛化为迭代器,参数化了所指向的对象的类型

独立的容器类型泛化为序列或关联容器,而且类似的容器拥有类似的功能。

标准的内存相邻容器都提供随机访问迭代器标准的基于节点的容器都提供双向迭代器

序列容器支持push_frontpush_back,但关联容器不支持。关联容器提供对数时间复杂度的lower_boundupper_boundequal_range成员函数,但序列容器却没有。

推行自己的容器

当你写你自己的容器、迭代器和算法时,你会自然而然地推行它。

很多人会试图在他们的软件中泛化容器的不同,而不是针对容器的特殊性编程,他们会想在vector 中使用 deque 或者 list的特性,这往往会带来麻烦。

比如:

  • 只有序列容器支持push_frontpush_back,只有关联容器支持countlower_bound

  • 即便是 inserterase这样的操作在名称和语义上也有差别

    • 把对象插入序列容器中,该对象会保留在你放置的位置上;
    • 当你把对象插入到一个关联容器中,容器会按照排列顺序把对象移到它应该在的位置;
  • 序列容器上用一个迭代器作为参数调用 erase,会返回一个新的迭代器;在关联容器上什么都不返回

容器能力的交集

如果你想写一个可以用在常用序列容器上的代码—— 包含vector, dequelist。你必须使用它们能力的交集来编写

但要考虑几点:

  • dequelist不支持reservecapacity
  • list 不支持operator[] 操作,且受限于双向迭代器的性能
  • 不能使用需要随机访问迭代器的算法,包括sortstable_sortpartial_sortnth_element
  • 如果想支持vector的规则,则不能使用push_frontpop_front
  • vectordeque都会使splice和成员函数方式的sort失败
  • 因为deque::insert使所有迭代器失效,而且因为缺少capacityvector::insert也必须假设使所有指针和引用失效,而deque是唯一一个在迭代器失效的情况下指针和引用仍然有效的东西
  • 不能把容器里的数据传递给C风格的界面,只有vector支持这么做
  • 不能用bool作为保存的对象来实例化你的容器,因为vector 并非总表现为一个vector,实际上它并没有真正保存bool值。
  • 不能期望享受到list的常数时间复杂度的插入和删除,vector和deque的插入和删除操作是线性时间复杂度的

所以,真正开发时,如果都考虑到上面几点,那想开发的容器只剩下一个“泛化的序列容器”,但是你不能调用reservecapacityoperator[]push_frontpop_frontsplice或任何需要随机访问迭代器的算法;调用inserterase会有线性时间复杂度而且会使所有迭代器、指针和引用失效;而且不能兼容C风格的界面,不能存储bool。

如果你放弃了序列容器,把代码改为只能和不同的关联容器配合,这情况并没有什么改善。

  • 要同时兼容setmap几乎是不可能的,因为set保存单个对象,而map保存对象对。
  • 甚至要同时兼容setmultiset(或mapmultimap)也是很难的。
  • set/mapinsert成员函数只返回一个值,和他们的multi兄弟的返回类型不同,而且你必须避免对一个保存在容器中的值的拷贝份数作出任何假设。
  • 对于mapmultimap,你必须避免使用operator[],因为这个成员函数只存在于map中。

面对疾风吧:

这根本没有必要。不同的容器是不同的,而且它们的优点和缺点有重大不同。它们并不被设计成可互换的,而且你做不了什么包装的工作。如果你想试试看,你只不过是在考验命运,但命运并不想被考验。

封装

如果想改变容器类型,就使用封装

Method1: typedef

一种最简单的方法是通过自由地对容器和迭代器类型使用typedef

class Widget {...};
vector<Widget> vw;
Widget bestWidget;
... // 给bestWidget一个值
vector<Widget>::iterator i =  // 寻找和bestWidget相等的Widget
find(vw.begin(), vw.end(), bestWidget);

可以简化上述写法

class Widget { ... };
typedef vector<Widget> WidgetContainer;
typedef WidgetContainer::iterator WCIterator;
WidgetContainer cw;
Widget bestWidget;
...
WCIterator i = find(cw.begin(), cw.end(), bestWidg

如果需要加上用户的allocator,也特别方便。(一个不影响对迭代器/指针/参考的失效规则的改变)

class Widget { ... };
template<typename T> // 关于为什么这里需要一个template
SpecialAllocator { ... }; // 请参见条款10
typedef vector<Widget, SpecialAllocator<Widget> > WidgetContainer;
typedef WidgetContainer::iterator WCIterator;
WidgetContainer cw; // 仍然能用
Widget bestWidget;
...
WCIterator i = find(cw.begin(), cw.end(), bestWidget); // 仍然能用

typedef只是其它类型的同义字,所以它提供的的封装是纯的词法(译注:不像#define是在预编译阶段替换的)。typedef并不能阻止用户使用(或依赖)任何他们不应该用的(或依赖的)。

Method2: class

要限制如果用一个容器类型替换了另一个容器可能需要修改的代码,就需要在类中隐藏那个容器,而且要通过类的接口限制容器特殊信息可见性的数量。

比如需要隐藏 真实的容器 list 建立客户列表:

class CustomerList {
private:
typedef list<Customer> CustomerContainer;
typedef CustomerContainer::iterator CCIterator;
CustomerContainer customers;
public: // 通过这个接口
... // 限制list特殊信息的可见性
};

如果使用过程中,你发现从列表的中部插入和删除客户并不像你想象的那么频繁,仅仅需要快速确定客户列表顶部的20%——一个为nth_element算法量身定做的任务。

nth_element需要随机访问迭代器,不能兼容list

在这种情况下,你的客户“list”可能更应该用"vector"或"deque"来实现

当你决定作这种更改的时候,你仍然必须检查每个CustomerList的成员函数和每个友元,看看他们受影响的程度(根据性能和迭代器/指针/引用失效的情况等等)

但如果你做好了对CustomerList地实现细节做好封装的话,那对CustomerList的客户的影响将会很小。


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

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

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

相关文章

大数据学习:kafka-producer源码分析

kafka-producer源码分析 kafka-1.0.1源码下载地址 一.kafka发送示例 /*** Created by XiChuan on 2021/6/7.*/ public class ProducerTest {public static void main(String[] args) throws Exception {KafkaProducer<String, String> producer createProducer();JSO…

企业为什么需要IM “定制化”?

企业内外部的信息交流作为一种刚需&#xff0c;证明了企业级 IM 市场稳定可靠且前景十足的商业价值。不过&#xff0c;标准化的企业 IM 产品由于定制化能力不足&#xff0c;容易形成封闭的产品生态&#xff0c;对于企业管理者的吸引力正逐渐减弱。 WorkPlus作为一个企业数字化…

电子科大软件系统架构设计——系统分析与设计概述(含课堂作业、练习答案)

系统分析与设计概述 信息系统概述 what 信息系统是一种能够完成对业务数据进行采集、转换、加工、计算、分析、传输、维护等信息处理&#xff0c;并能就某个方面问题给用户提供信息服务的计算机应用系统。 组成 信息化基础设施&#xff08;计算机、计算机网络、服务器、系统…

git文件夹内容详解

.git文件夹是Git版本控制系统在项目根目录下创建的隐藏文件夹&#xff0c;包含了Git仓库的所有相关信息。如下是.git文件夹中常见的一些内容及其作用&#xff1a; HEAD&#xff1a;指向当前所在的分支&#xff08;或者是一个特定的提交&#xff09;。 branches&#xff1a;存储…

SoftwareTest1 - 打破你对软件测试的偏见

软件测试答疑篇 一 . 什么是软件测试二 . 软件测试和软件开发的区别2.1 难易程度2.2 工作环境2.3 薪水("钱"景)2.4 繁忙程度2.5 测试和研发中调试的区别 三 . 软件测试岗位四 . 软件测试人员应该具备的素质4.1 综合能力4.2 优秀的测试用例设计能力4.3 掌握自动化测试…

ShardingSphere——柔性事务SEATA原理

摘要 Apache ShardingSphere集成了 SEATA 作为柔性事务的使用方案&#xff0c;本文主要介绍其实现ShardingSphere中柔性事务SEATA原理原理。帮助你更好的理解ShardingSphere原理。同时帮助大家更好的使用柔性事务SEATA原理。 一、Seata柔性事务 Apache ShardingSphere 集成了…

合并区间【贪心算法】

合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 class Solution {public int[][] merge(int[…

uniapp 配置并使用 VueX

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 uni-app 内置了 VueX 1、创建需要的文件 右键点击 根目录【我的是 uni-shop】&#xff0c;然后新建 目录&a…

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

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

轻松管理不同类型的文件,高效将文件按类型进行移动归类

如果你经常需要处理不同类型的文件素材&#xff0c;例如图片、音频、视频等&#xff0c;那么你一定知道这是一项繁琐的任务。为了帮助你快速整理这些文件&#xff0c;我们推出了一款强大的文件管理工具&#xff0c;让你能够轻松地将不同类型的文件素材归类到不同文件夹里单独保…

功率信号源的用途和作用有哪些

功率信号源是一种重要的电子设备&#xff0c;用于生成具有特定功率水平、波形和频率的电压或电流信号。它在各种应用中发挥着关键作用。下面介绍功率信号源的主要用途和作用&#xff1a; 电路测试和调试&#xff1a;功率信号源被广泛应用于电路测试和调试过程中。它可以提供不同…

SAP PP之定义活动/作业类型(Activity Type)

文章目录 前言 一、作业是什么 二、使用步骤 1.单独创建 2.创建组 注意点 前言 创建活动类型具有以下先决条件&#xff1a; 控制范围已创建并分配给公司代码。已创建成本要素类别为43的次要成本要素。 一、作业是什么 SAP活动类型是在成本范围的成本中心中产生的活动的分类。…

【JUC基础】JUC入门基础(二)

目录 异步回调JMM 理解对 volatile 的理解1、保证可见性2、不保证原子性3、禁止指令重排 对 JMM 的理解 详解单例模式饿汉式懒汉式DCL懒汉式&#xff1a;双重检测锁模式的懒汉式单例静态内部类实现单例通过反射破坏单例&#xff0c;修改后的DCL饿汉式枚举实现单例防止反射破坏 …

不需要Photoshop!这10款替代软件也能轻松处理图片

Photoshop是一款功能强大的图像处理工具&#xff0c;很多人说到修图就会想到要用PS&#xff0c;但是Photoshop是要付费的&#xff0c;对于业余设计师或者对修图需求量不太高的普通用户来说&#xff0c;使用Photoshop的成本略高。本篇文章&#xff0c;我们向你推荐5款Photoshop替…

FreeRTOS的信号量和互斥量之间的区别和联系

文章目录 信号量信号量简介信号量特征 互斥量互斥量的上锁机制互斥量的优先级继承机制 二值信号量和互斥量的作用二值信号量的作用互斥量的作用 二值信号量和互斥锁关系相同点不同点 如何根据场景选择回答信号量和互斥锁之间的区别&#xff1a; 信号量 信号量简介 队列(queue)…

Unity AssetBundle(1):Assets打包和依赖(Dependencies)

对Unity5.x后的AssetBundle依赖机制有了一点理解&#xff0c;创建了一个项目验证 github:GeWenL / AssetBundlePro AbScene.unity 资源有哪些&#xff1f; Some common types of Asset assetbundle打包命令是 BuildPipeline.BuildAssetBundles ,格式有&#xff1a; 引用&…

vue3+ts组件通信

1、父组件向组件传参 父组件代码 子组件代码 2、子组件向父组件传参 组件间代码 父组件代码 3、如果eslint报错&#xff0c;需在.eslintrc.js中添加一行代码 4、通过父组件通过 ref 获取子组件的属性或者方法 父组件代码 子组件代码 5、孙子组件provide和inject 父组件…

重磅!腾讯云 CODING 入选软件供应链产品名录

点击链接了解详情 2023 年 8 月 25 日&#xff0c;由中国信息通信研究院、中国通信标准化协会联合主办的**“2023 首届 SecGo 云和软件安全大会”在京召开。会上正式发布了第二期《软件供应链厂商和产品名录》&#xff0c;旨在提升软件供应链透明度&#xff0c;宣传推广一批成熟…

Ceph构件及组件分析

Ceph存储架构 Ceph 存储集群由几个不同的daemon组成&#xff0c;每个daemon负责Ceph 的一个独特功能并。每个守护进程是彼此独立的。 下面将简要介绍每个Ceph组件的功能&#xff1a; RADOS&#xff08;Reliable Autonomic Distributed Object Store, RADOS&#xff09; RADOS…

Python面向对象编程(一)类的基础,关系,继承,封装,多态

类的一些理论概念及其应用场景等基础内容此处不赘述 目录 类的定义及基础 属性 方法 初始化方法 普通方法 类之间的关系 相互调用 依赖关系 关联关系 组合关系 三大特征----类的继承 重写父类方法 多继承 三大特征----封装 三大特征----多态 类的定义及基础 类…