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 测试使用固定公网地址…

微信小程序 - 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…

万物流动 万物永驻 ——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…

说说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&…

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

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

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 …

从项目中突显技能:在面试中讲述你的编程故事

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【飞书ChatGPT机器人】飞书接入ChatGPT,打造智能问答助手

文章目录 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 前言 在飞书中创建chatGPT机器人并且对话&#xff0c;在下面操作步骤中…

结构体的简单介绍

目录 概念&#xff1a; 与数组类比&#xff1a; 结构体声明&#xff1a; 注意&#xff1a; 结构体变量、全局变量、局部变量&#xff1a; 结构体声明中包含其他结构体变量&#xff1a; 结构体变量的初始化&#xff1a; 包含了其他结构体变量的初始化&#xff1a; 结构体…

SPI2外设驱动-W25Q64 SPI接口初始化

前言 &#xff08;1&#xff09;本系列是基于STM32的项目笔记&#xff0c;内容涵盖了STM32各种外设的使用&#xff0c;由浅入深。 &#xff08;2&#xff09;小编使用的单片机是STM32F105RCT6&#xff0c;项目笔记基于小编的实际项目&#xff0c;但是博客中的内容适用于各种单片…

【FlowDroid】一、处理流程学习

FlowDroid 一、处理流程学习 下载配置源码概况代码逻辑分析analyzeAPKFilerunInfoflowprocessEntryPointcalculateCallbacks(sourcesAndSinks)再次回到processEntryPoint 自己做一些笔记 下载配置 参照我前面的文章可以使用FlowDroid安装初体验 为了看代码了解FlowDroid如何处…

homeassistant ubuntu自启动 网络设置

命令行安装virtualbox 或者安装包 hass官网下载 haos_ova-10.4.vdi virtualbox 装hass 最少2G内存 其他省略 自启动&#xff1a; gnome-session-properties 添加 VBoxManage startvm hass --type headless hass为自己的虚拟机名字 网络配置如下&#xff1a; 要全部打开

【云原生】Kubernetes容器编排工具

目录 1. K8S介绍 1.1 k8s的由来 下载地址 1.2 docker编排与k8s编排相比 1.3 传统后端部署与k8s 的对比 传统部署 k8s部署 ​2. k8s的集群架构与组件 &#xff08;1&#xff09; Kube-apiserver &#xff08;2&#xff09;Kube-controller-manager &#xff08;3&a…