参考链接:http://blog.csdn.net/haotiangg/article/details/76266579

第一章 容器

第1条:慎重选择容器类型:选择合适的容器很关键!

C++中各种标准或非标容器:
标准STL序列容器:    vector、string、deque和list(双向列表)。
标准STL关联容器:    set、multiset、map和multimap。
非标准STL序列容器: slist(单向列表)和rope(重型字符串?)。
非标准STL关联容器: hash_set、hash_multiset、hash_map和hash_multimap。(c++11引入了unordered_set、unordered_multiset、unordered_map和unordered_multimap,其亦基于hash表,但属于最新的标准关联容器,所以相对hash_*拥有更高的效率和更好的安全性)
标准非STL容器:    数组(c++11中有新的array标准)、bitset、valarray(用于数值计算,但是一般很少使用)、stack、queue和priority_queue(常用于模拟最大堆和最小堆)
其他:    vector<char>在某些情况下可以替换string, vector在某些情况下可以替换标准关联容器。

不要使用 vector<bool>,vector<bool>不是容器,至少,不是标准意义上的容器。C++标准对于vector<bool>值有其特殊的实现方法。目的是为了减小空间的耗用。特殊版本内部只使用一个bit来存储一个元素,所以通常要比一般的bool值小8倍之多。建议使用deque<bool>替代之。

选择参考:

  1. 如果需要在容器的任意位置插入新元素,就选择序列容器;关联容器是不行的。
  2. 是否关心容器中的元素是如何排序的?如果不关心,则hash容器是一个可以的选择;否则,你要避免hash容器。
  3. 选择容器必须是标准C++的一部分吗,如果必须是,就排除了hash容器(疑惑:我怎么记得hash容器已经成为标准了呢?)、slist和rope。
  4. 当发生元素的插入或删除操作时,若需要避免移动容器中原来的元素,就要避免连续内存的容器。vector
  5. 容器中数据的布局需要和C兼容,则只能选择vector。
  6. 元素的查找速度是否很关键,如果是,则考虑hash容器、排序的vector和标准关联容器。
  7. 如果容器内部使用了引用计数技术,你是否介意?如果是,就要避免使用string和rope。可以用vector<char> 替代string。

面对不同的情形,选择合适的容器!

第二条:小心对“容器无关代码”(container-independent code)的幻想。

本条款要告诫程序员:编写与容器无关的代码是没有必要的。

STL是建立在泛型的基础上,但由于不同容器的特性不同(尤其是迭代器、指针和引用的类型与失效规则不同),支持所有容器的相同接口是不存在的。比如:
只有序列容器支持: push_front和push_back,
只有关联容器支持: logN时间复杂度的lower_bound、upper_bound和equal_range;
如果在工程中需要跟换容器类型,可以通过用typedef来减少跟换所带来的代码跟新量。

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

同样,typedef可以用来简化一个经常被运用到的容器的定义,并减少维护的成本。但是typedef只是其他类型的同义字,
如果不想暴露所使用的容器类型,可以将所用的容器封装到一个class中。可以在这个class实现额外的功能,并对原始容器的操作进行封装。

第三条:确保容器中的对象拷贝正确而高效:

容器容纳了对象,但不是你给它们的那个对象。当你向容器中插入一个对象时,你插入的是该对象的拷贝而不是它本身;当你从容器中获取一个对象时,你获取的是容器中对象的拷贝。

拷贝对象是STL的基本工作方式。当你删除或者插入某个对象时,现有容器中的元素会移动(拷贝);当你使用了排序算法,remove、uniquer或者他们的同类,rotate或者reverse,对象会移动(拷贝)。

一个使拷贝更高效、正确的方式是建立指针的容器而不是对象的容器,即保存对象的指针而不是对象,然而,指针的容器有它们自己STL相关的头疼问题,改进的方法是采用智能指针。

第四条:调用empty而不是检查size()是否为0

对于任意容器c,写下

if (c.size() == 0)…

本质上等价于写下

if (c.empty())…

但是为什么第一种方式比第二种优呢?理由很简单:对于所有的标准容器,empty是一个常数时间的操作,但对于一些list实现,size花费线性时间。

这什么造成list这么麻烦?为什么不能也提供一个常数时间的size?如果size是一个常数时间操作,当进行增加/删除操作时每个list成员函数必须更新list的大小,也包括了splice,这会造成splice的效率降低(现在的splice是常量级的),反之,如果splice不必修改list大小,那么它就是常量级地,而size则变为线性复杂度,因此,设计者需要权衡这两个操作的算法:一个或者另一个可以是常数时间操作。

第五条:尽量使用区间成员函数代替单元素操作

给定两个vector,v1和v2,怎样使v1的内容和v2的后半部分一样?
可行的解决方案有:

(1)使用区间函数assign:

v1.assign(v2.begin() + v2.size() / 2, v2.end());

(2)使用单元素操作:

vector<Widget>::const_iterator ci = v2.begin() + v2.size() / 2;
ci != v2.end();
++ci)
v1.push_back(*ci);

(3)使用copy区间函数:

v1.clear();
copy(v2.begin() + v2.size() / 2, v2.end(), back_inserter(v1));

(4)使用insert区间函数:

v1.insert(v1.end(), v2.begin() + v2.size() / 2, v2.end());

最优的方案是assign方案,理由如下:

首先,使用区间函数的好处是:
● 一般来说使用区间成员函数可以输入更少的代码。
● 区间成员函数会导致代码更清晰更直接了当。

使用copy区间函数存在的问题是:
【1】 需要编写更多的代码,比如:v1.clear(),这个与insert区间函数类似
【2】 copy没有表现出循环,但是在copy中的确存在一个循环,这会降低性能

单元素变量操作指运用循环,将单个元素一一进行的操作,这类操作主要是插入(insert,push_front,push_back)和删除操作(erase)。值得注意的是如下copy操作虽然看起来是区间操作,其本质上还是单元素操作。

使用insert单元素版本的代码对你征收了三种不同的性能税,分别为:
【1】 没有必要的函数调用;
【2】 无效率地把v中的现有元素移动到它们最终插入后的位置的开销;
【3】 重复使用单元素插入而不是一个区间插入必须处理内存分配。

使用区间操作的好处是什么呢?以insert函数为例:一、减少函数调用,区间操作只需调用一次insert(),而单元素操作需要调用N次insert();二、对于内存连续型容器,每次插入时,需要移动后面的所有元素。所以区间操作只需移动一次,而单元素操作需要移动N次(list型不需要移动元素,但需要设置prev和next指针,也会造成类似的效率影响);三、对于vector和string,当所分配内存已满,需要重新分配内存并移动容器内已有元素。区间操作会实现计算所需内存,只需最多一次的内存重新分配和元素移动,而但单元素操作需要logN次内存重新分配和元素移动。

下面进行总结:
说明:参数类型iterator表示容器的迭代器类型,也就是container::iterator,参数类型InputIterator表示可以接受任何输入迭代器。

【1】区间构造
所有标准容器都提供这种形式的构造函数:

container::container(InputIterator begin, // 区间的起点
InputIterator end); // 区间的终点

【2】区间插入
所有标准序列容器都提供这种形式的insert:

void container::insert(iterator position, // 区间插入的位置
InputIterator begin, // 插入区间的起点
InputIterator end); // 插入区间的终点

关联容器使用它们的比较函数来决定元素要放在哪里,所以它们了省略position参数。

void container::insert(lnputIterator begin, InputIterator end);

【3】区间删除
每个标准容器都提供了一个区间形式的erase,但是序列和关联容器的返回类型不同。序列容器提供了这个:

iterator container::erase(iterator begin, iterator end);

而关联容器提供这个:

void container::erase(iterator begin, iterator end);

为什么不同?解释是如果erase的关联容器版本返回一个迭代器(被删除的那个元素的下一个)会招致一个无法接受的性能下降.

【4】区间赋值
所有标准列容器都提供了区间形式的assign:

void container::assign(InputIterator begin, InputIterator end);

《Effective STL》读书笔记之容器1-5相关推荐

  1. Effective STL 读书笔记

    Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...

  2. Effective STL读书笔记

    第一章容器 条款1:仔细选择你的容器 C++中各种标准或非标容器: 标准STL序列容器:    vector.string.deque和list(双向列表). 标准STL管理容器:    set.mu ...

  3. Effective C++读书笔记 摘自 pandawuwyj的专栏

    Effective C++读书笔记(0)       Start   声明式(Declaration):告诉编译器某个东西的名称和类型,但略去细节.   std::size_t numDigits(i ...

  4. more effective c++和effective c++读书笔记

    转载自http://bellgrade.blog.163.com/blog/static/83155959200863113228254/,方便日后自己查阅, More Effective C++读书 ...

  5. Effective Java读书笔记(二)

    Effective Java 读书笔记 (二) 创建和销毁对象 遇到多个构造器参数时要考虑使用构建器 创建和销毁对象 何时以及如何创建对象? 何时以及如何避免创建对象? 如何确保它们能够适时地销毁? ...

  6. Effective Java 读书笔记(七):通用程序设计

    Effective Java 读书笔记七通用程序设计 将局部变量的作用域最小化 for-each 循环优于传统的 for 循环 了解和使用类库 如果需要精确的答案请避免使用 float 和 doubl ...

  7. Effective C++ 读书笔记 Item1-Item4

    目录 守则01:把C++看做一个语言的集合,而不是单一的语言 守则02:尽量使用const, enum, inline, 减少宏变量#define的使用 守则03: 尽可能使用const关键字 守则0 ...

  8. Effective C++读书笔记(一)

    百度博客本来就垃圾,我以前发表的文章也全是废品.就在csdn这里放上我的读书笔记,自娱自乐下. 1 让自己习惯C++ 条款01:视C++为一个语言联邦 C语言同时支持过程形式(procedural). ...

  9. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  10. Effective Java 读书笔记(一)

    前言: 开个新的坑位,<effective java>的读书笔记,之后有时间会陆陆续续的更新,读这本书真的感触满多,item01和item02就已经在公司的项目代码中看到过了.今天这篇主要 ...

最新文章

  1. 2009计算机统考真题,2009年计算机统考真题(完整版).PDF
  2. tl wn322g linux驱动下载,TL-WN322G+ 2.0_WN422G+ 2.0驱动程序
  3. 整数中1出现的次数(从1到n整数中1出现的次数)
  4. JavaScript从入门到放弃 -(四)E5 新增方法
  5. 如果删除网上服务器登陆账号密码,怎么清除SVN的用户名和密码
  6. 12.6-12.9 Nginx安装,默认虚拟主机,用户认证,域名重定向
  7. 登顶 GitHub 趋势榜,标星1.8k:200 行 JS 代码让画面人物瞬间消失!
  8. TurboMail成功建设某省建工集团邮件系统
  9. GeoServer服务器环境的搭建
  10. 企业微信SCRM怎么弄永久群二维码?可以实现社群私域流量裂变吗?
  11. bugzilla mysql 配置_Bugzilla环境安装和配置手册
  12. 在线下单系统think php,昱杰订单管理系统(ThinkPHP版) v19.0
  13. 我们公司使用了 5 年的系统限流方案 ,从实现到部署实战详解,稳的一B
  14. GlobalSign是什么,其中的ssl证书类型有哪些
  15. 一些个人推荐的优秀博客
  16. Ubuntu1804安装
  17. 【正则表达式】自动生成各类正则代码
  18. RNN经典案例(人名分类器)
  19. 新手必读:一个牛人给的java九点建议
  20. 正轴等距离切圆柱投影

热门文章

  1. 15天共读深度学习Day6
  2. 免费英文版的SEO优化工具使用教程
  3. 抖音 TikTok蝉联全球移动应用收入冠军
  4. 小船翻了,路还得继续
  5. Navicat导入Sql文件不成功
  6. 百度竞价点击器_哪些因素影响百度竞价点击量
  7. CLion调试redis6源码
  8. 爵士、古典、摇滚、流行音乐
  9. 华容道6×6图解_全民主公华容道6-10关通关布阵图推荐解析
  10. 碎碎念 2022.4.25