Effective STL笔记(一)
来源:互联网 发布:季汉 知乎 编辑:程序博客网 时间:2024/05/21 10:52
第1条慎重选择容器类型
序列容器:
vector, string, deque, list
关联容器:
set, multiset, map, multimap
非标准序列容器:
hash_set, hash_multiset, hash_map, hash_multimap
非标准STL容器:
数组, bitset, valarray, stack, queue, priority_queue
第2条不要试图编写独立于容器类型的代码
不要想着对容器的概念泛化。比如使用vector,但仍保留以后将其换成deque或list的选择,而不必改变使用该容器的代码。如果这样做,则该程序只能使用这些容器的功能的交集。如reserve或capacity只在vector中有,deque和list中不存在这样的操作。进一步,还得把操作限制在双向迭代器的能力范围,而sort,stable_sort,partial_sort,nth_element都需要随机访问迭代器。
不同容器是不同的。它们有非常明显的优缺点。它们并不是被设计来交换使用的。(所以,需要“慎重选择容器类型”!!!)
若考虑以后可能会不可避免的从一种容器类型转换到另一种,可以使用“封装(encapsulation)技术”。最简单的方式是通过对容器类型和其迭代器类型使用类型定义(typedef)。(有用,但在此效果不大。)
另外一种方法是使用“类(class)”。并尽量减少那些通过类接口(而使外部)可见的、与容器相关的信息。
第3条 确保容器中的对象拷贝正确而高效
向容器中加入对象时,存入容器的是该对象的拷贝(按位拷贝或用户自定义的拷贝)。这将带来两个问题。
一、拷贝操作可能很费时,向容器填充对象这一简单操作可能成为性能瓶颈
二、存在继承关系时,拷贝操作可能会发生剥离(slicing)。一个存放基类对象的类,却向其插入派生类的对象,则派生类对象被拷贝进容器后,它所特有的部分(派生类中的信息)将会丢失。
解决上两个问题的一个简单操作是使容器包含指针而不是对象。拷贝指针的速度快,并且不会有剥离现象发生(多态)。第7条和第33条描述了使用指针容器的一些问题。使用智能指针(smart pointer)是一个诱人的选择。
第4条 调用empty而不是检查size()是否为0
empty操作对所有的标准容器都是常数时间操作,而对于一些list的具体实现,size()可能是线性时间的操作。
原因在于list的splice()操作。该操作会影响list对象的元素个数。
list<int>list1;list<int>list2;…list1.splice(list1.end(),list2, find(list2.begin(),list2.end(), 5), list2.end());
这段操作将list2中的一段区间移动到list1中。该操作过后,list1和list2中的元素个数都将改变,那选择在这时候更新list中的元素个数的记录(遍历两个list),使该splice()操作成为线性时间的操作;还是选择在需要获取list元素个数时才遍历list,而使splice()成为常数时间的操作?这是个tradeoff!!!(sgi选择的是使size()遍历list,保持splice()操作的常数时间)
第5条 区间成员函数优先于与之对应的单元素成员函数
两个vector v1和v2,将v2中的元素附加到v1的尾部,是一个一个的加入
for(it =v2.begin(); it != v2.end(); ++it){ v1.push_back(*it);}
还是使用
v1.insert(v1.end(),v2.begin(), v2.end());
- 使用区间成员函数,通常可以少写一写代码
- 使用区间成员函数,通常会得到意图清晰和更加直接的代码。
在效率上,使用单元素的成员函数比使用区间成员函数(可能)需要更多地调用内存分配子,更频繁的拷贝对象,而且/或者做冗余的操作。
另外,如果想把v2中的元素按原顺序插入到v1的头部的话,使用for循环需要这样
for(it =v2.rbegin(); it != v2.rend(); ++it){ v1.push_front(*it);//push_front操作完全没效率 //或者 v1.insert(v1.begin(), it.base()-1);}
而
v1.insert(v1.begin(),v2.begin(), v2.end());
可以一次性分配需要的内存,避免一次又一次的重复分配内存。
对区间操作函数总结如下
- 区间创建:所有标准容器都提供了如下形式的构造函数
container::container(InputIterator begin, InputIterator end);
- 区间插入:所有标准序列容器都提供了如下形式的insert:
void container::insert(iterator position, InputIterator begin, InputIterator end);
关联容器利用比较函数决定元素插入何处,所以:
void container::insert(InputIterator begin, InputIterator end);
省去了position参数。
- 区间删除:所有标准容器都提供了区间形式的删除(erase)操作。对于序列容器,
iterator container::erase(iterator begin, iterator end);
而关联容器则是这样:
void container::erase(iterator begin, iterator end);
返回值不同。这是因为据说对于关联容器,返回删除元素之后的元素的迭代器将导致不可接受的性能负担。
- 区间赋值:所有标准容器都提供了区间形式的assign:
void container::assign(InputIterator begin, InputIterator end);
- Effective STL笔记(一)
- Effective STL笔记一-容器
- Effective STL学习系列--笔记一
- Effective STL 第一章:容器(一)
- 阅读effective stl 有感(一)
- Effective STL (一)
- copy_if函数(effective STL学习笔记)
- 《Effective STL》学习笔记(第一部分)
- 《Effective STL》学习笔记(第二部分)
- 《Effective STL》学习笔记(第三部分)
- 《Effective STL》学习笔记(第四部分)
- 《Effective STL》学习笔记(第一部分)
- 《Effective STL》学习笔记(第二部分)
- 《Effective STL》学习笔记(第三部分)
- 《Effective STL》学习笔记(第四部分)
- effective stl 笔记
- Effective STL 笔记
- Effective STL 笔记
- <<C++程序设计原理与实践>>粗读 -- chapter8 Chapter9
- 取模和取余的区别
- Windows7(x64)下Oracle10g安装
- 安全基础:搭建VM环境 调试WRK内核
- 网络广告术语说明
- Effective STL笔记(一)
- 辞旧迎新——年度web开发合辑,新年大放送
- verilog 入门共阳极流水灯
- VMWare+WinDbg搭建(驱动)调试环境
- 错排
- Android模拟器学framework和driver之传感器篇0(导读)
- 获取进程句柄的数量
- 寒假篇 - 3
- 电信3G天翼宽带与SP1冲突导致WIN7桌面AERO半透明效果无法开启