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

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.mzph.cn/news/62350.shtml

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

相关文章

如何通过内网穿透实现外部网络对Spring Boot服务端接口的HTTP监听和调试?

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

Python爬虫:打开盈利大门的利器

导言&#xff1a; 随着互联网的迅速发展&#xff0c;越来越多的企业和个人开始意识到数据的重要性。而Python爬虫作为一种自动化获取互联网信息的技术&#xff0c;为人们提供了更便捷、高效的数据获取方式。本文将介绍基于Python爬虫的五种盈利模式&#xff0c;并提供实际案例…

微信小程序 - 2023年最新版手机号快捷登录详细教程

前言 最近开发公司手机快捷登录的功能&#xff0c;花费了不少时间&#xff0c;这里附上详细教程。 这里以海底捞小程序的图片为例&#xff0c;如有侵权请联系小编删除。 代码如下 <button open-type"getPhoneNumber" getphonenumber"getPhoneNumber"…

oracle 基础运用2

首先在电脑上安装PLSQL developer&#xff0c;这个是oracle图形化连接工具&#xff0c;然后安装win64_11gR2_client&#xff0c;这个是orace客户端&#xff0c;安装完成后可以在cmd命令行输入sqlplus命令进行验证&#xff0c;如图表示安装成功。 作为sys的连接应该是SySDBA或Sy…

一些关于异构SOC IPC核间通信的知识

帮你了解一些关于异构SOC IPC核间通信的知识。 异构SOC是指在一个芯片上集成了不同类型的处理器核&#xff0c;例如ARM、DSP、GPU等&#xff0c;它们可以协同工作&#xff0c;提高性能、降低功耗、节省成本和空间。 IPC&#xff08;Inter-Processor Communication&#xff0…

vxe-table全选禁用并保留选中项

需求&#xff1a;1、新建时全选可用&#xff0c;提交后全选不可用&#xff1b;2、提交后新建时选中的记录还要保持选中状态 官网上写的是可以通过 strict 设置为严格模式&#xff0c;当表格中不存在有效数据时列头复选框为禁用状态。 通过设置strict可以实现第一个需求&#…

万物流动 万物永驻 ——C++ Core Guidelines的流动哲学

众所周知&#xff0c;C 是一门自由的语言&#xff0c;语言的设计哲学之一就是赋予程序员极大的自由度和灵活性&#xff0c;因此&#xff0c;使用C 完成一个任务时&#xff0c;不同的程序员往往会有不同的实现方法&#xff0c;这真正阐释了什么叫条条大路通罗马。不过&#xff0…

Android Activity 启动流程 二:setContentView

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、概览二、setContentView&#xff08;&#xff09;三…

阿桂天山的技术小结:Flask+UEditor实现图片文件上传富文本编辑

话不多说,有图有源码 先看效果: 1.前端html页面index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><script src"{{ url_for(static,filenameueditor/ueditor.config.js) }}"></script…

数学建模:灰色关联分析

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 灰色关联分析法 算法流程 建立一个m行 n列的矩阵 X X X &#xff0c;其中 m 表示评价对象&#xff0c; n表示评价指标首先进行矩阵的归一化&#xff0c;得到归一化后的矩阵 d a t a data data获取参考向…

说说Flink中的State

分析&回答 基本类型划分 在Flink中&#xff0c;按照基本类型&#xff0c;对State做了以下两类的划分&#xff1a; Keyed State&#xff0c;和Key有关的状态类型&#xff0c;它只能被基于KeyedStream之上的操作&#xff0c;方法所使用。我们可以从逻辑上理解这种状态是一…

[第七届蓝帽杯全国大学生网络安全技能大赛 蓝帽杯 2023]——Web方向部分题 详细Writeup

Web LovePHP 你真的熟悉PHP吗&#xff1f; 源码如下 <?php class Saferman{public $check True;public function __destruct(){if($this->check True){file($_GET[secret]);}}public function __wakeup(){$this->checkFalse;} } if(isset($_GET[my_secret.flag]…

【Java Web】敏感词过滤

一、前缀树 假设有敏感词&#xff1a;b&#xff0c;abc&#xff0c;abd&#xff0c;bcd&#xff0c;abcd&#xff0c;efg&#xff0c;hii 那么前缀树可以构造为&#xff1a; 二、敏感词过滤器 package com.nowcoder.community.util;import org.apache.commons.lang3.CharUt…

全网首发!大众宝来高尔夫polo领驭迈腾帕萨特奥迪A4A6B6B7等老车机增加带蓝牙控制的AUX解码模块,支持小程序原车按钮控制,支持外接高品质蓝牙模块

文章目录 前言1、设计指标2、PCB设计3、程序设计4、调试4.1蓝牙控制AUX解码板4.2自定义车机按钮控制其他高品质蓝牙音频模块4.3小程序使用 5、模块与车机连接方法6、结语 前言 ​ 之前写过四篇关于车机增加音频输入的方法。 1、07宝来经典车机CD收音机&#xff08;RC668&…

【Python】python使用docxtpl生成word模板

python使用docxtpl生成word模板 python-docxtpl包简单使用和实战&#xff0c;Python处理word&#xff0c;docx文件。 最近需要处理一些爬虫得到的数据来进行一些自动化报告的操作&#xff0c;因为需要生成的是word的报告&#xff0c;所以估选用docxtpl库来直接生成模板 docxt…

前端需要理解的数据治理与异常监控知识

服务监控包括错误监控、性能监控和行为监控。数据埋点是对服务监控中收集用户信息的技术实现&#xff0c;分为侵入式和非侵入式。 1 数据治理 前端数据治理的重要指标是准确性和数据&#xff0c;一个数据对象包括数据值和其他元数据。 2 数据上报方式 2.1 Image 通过将采集…

nodejs发布静态https服务器

1、先用 npm init 创建一个package.json&#xff0c;然后添加依赖 node-static &#xff0c;package.json 如下&#xff1a; {"name": "freeswitch","version": "1.0.0","description": "test freeswitch for webrtc&…

20种数据相似性计算方法

不同的相似性计算方法适用于不同类型的数据和问题。在选择相似性计算方法时&#xff0c;需根据数据的特性、问题的定义以及所关注的数据特点来做出合适的选择。 本文归纳了20种数据相似性计算方法以及它们的特点和适用场景&#xff0c;并给出了参考python实现。 相似性计算方法…

windows10默认浏览器总是自动更改为Edge浏览器

在设置的默认应用设置中把默认浏览器改为chrome或其他之后他自动又会改回Edge。不得不说*软真的狗。 解决办法&#xff1a; 后来发现在Edge浏览器的设置中有这么一个选项&#xff0c;会很无耻的默认是Edge。把它关掉后重新设置就行了。

NPM 常用命令(一)

目录 1、npm 1.1 简介 1.2 依赖性 1.3 安装方式 2、npm access 2.1 命令描述 2.2 详情 3、npm adduser 3.1 描述 4、npm audit 4.1 简介 4.2 审计签名 4.3 操作示例 4.4 配置 audit-level dry-run force json package-lock-only omit foreground-scripts …