STL学习笔记(一) 容器
0.前言
随机访问迭代器: vector、string、deque
STL的一个革命性的方面就是它的计算复杂性保证
条款01:慎重选择容器类型
c++提供的容器:
标准STL序列容器:vector、string、deque、list
标准STL关联容器:set、multiset、map、multimap
非标准STL容器:stack、queue、hash_set、hash_map
STL容器的一个分类方法:
连续内存容器:逻辑相邻的元素物理地址也相邻:vector、string、deque
基于节点的容器:逻辑相邻的元素的物理地址一般不相邻:list、set、map
条款02:不要试图编写独立于容器类型的代码
STL以泛化原则为基础:
数组被泛化为"以其包含的对象的类型为参数"的容器
指针被泛化为"以其指向的对象的类型为参数"的迭代器
函数被泛化为"以其使用的迭代器的类型为参数"的算法
条款03:确保容器中的对象拷贝正确而高效
当通过 insert、push_back 向容器中加入对象时,存入容器的是你所指定对象的拷贝
当通过 front、back 从容器中取出一个对象时,你所得到的是容器中所保存对象的拷贝
使拷贝动作高效、正确,并防止派生类对象剥离问题的一个简单办法就是:使容器包含指针而不是对象(智能指针)
void func() {
typedef std::tr1::shared_ptr<Widget> SPW;
std::vector<SPW> vpw;
for (int i = ; i < ; ++i)
vpw.push_back(SPW(new Widget)); //无内存泄露且异常安全
}
条款04:调用 empty 而不是 检查 size() 是否为0
if (c.size() == 0) 本质上与 if (c.empty()) 等价
我们应该总是调用 empty(),因为 empty() 操作对所有的标准STL容器都是O(1),size() 对某一些list容器是O(n) (不同平台list实现略有不同)
条款05:区间成员函数优先于与之对应的单元素成员函数
区间成员函数:使用两个迭代器参数来确定该成员操作所执行的区间
std::vector<int> vec1;
std::vector<int> vec2;
现在让vec1的整体与vec2 的后半部分相同:
(1)区间成员assign版本:
vec1.assign(vec2.begin() + vec2.size() / , v2.end());
//注:assign() 对所有的标准序列容器 vector、string、deque、list都适用,当需要完全替换一个容器的内容时,应该优先使用assign()
(2)单元素循环版本:
vec1.clear();
for (auto it = vec2.begin() + vec2.size() / ; it != vec2.end(); ++it)
vec1.push_back(*it);
(3)区间成员insert版本:
vec1.clear();
vec1.insert(vec1.end(), vec2.begin() + vec2.size() / , vec2.end());
假定把一个int数组拷贝到一个vector里面:
方法一:区间成员函数
int data[numValues];
vector<int> vec;
vec.insert(vec.begin(), data, data + numValues);
方法二:单元素循环
vector<int>::iterator it = vec.begin();
for (int i = ; i < numValues; ++i) {
it = vec.insert(it, data[i]);
++it;
}
注:任何push和insert操作都可能导致迭代器失效,当元素插入到vector、deque、string时,必须确保迭代器在每次循环后都得到更新
a.方法一之调用一次insert函数,方法二调用了numValues次insert函数
b.假设vec插入前已有n个元素,则方法二总共会有 n*numValues 次元素移动,如果元素为自定义类型,则会调用 n*numValues次赋值操作
方法一中,c++标准要求区间insert函数把现有容器中的元素直接移动到他们的最终位置,总共会有 n 次元素移动
c.方法二使用区间insert可以在元素插入之前计算需要多少新内存,从而只进行一次 vector的内存扩充操作
方法一单元素循环插入numValues次最多可导致log(numValues)次新内存分配(涉及到新内存分配、元素拷贝到新内存、旧内存回收)
区间函数:
(1)区间创建:所有标准容器提供如下形式的构造函数
container::container(InputIterator begin, InputIterator end);
(2)区间插入:所有标准序列容器提供如下形式的 insert
container::insert(iterator pos, InputIterator begin, InputIterator end);//元素在pos之前插入
所有标准关联容器提供如下形式的insert:
container::insert(InputIterator begin, InputIterator end);//关联容器使用比较函数来决定元素该插入何处
(3)区间删除:所有标准容器提供如下形式的 erase
container::erase(iterator begin, iterator end);
(4)区间赋值:所有标准序列容器都提供如下形式的 assign
container::assign(InputIterator begin, InputIterator end);
总结:应该优先使用区间成员函数而不是单元素循环版本,因为使用区间可以预先知道操作结果,从而一次性移动到最终位置
条款06:当心c++编译器最烦人的分析机制
当区间创建函数 container::container(InputIterator begin, InputIterator end) 使用的迭代器是 istream_iterator时可能遇到c++最烦人的分析机制
条款07:容器中包含 new 创建的指针,必须在对象析构之前 delete 掉(注:采用 shared_ptr,避免人肉 delete)
条款08:采用shared_ptr智能指针,禁止使用auto_ptr
条款09:慎重选择删除元素的方法
假如有以下标准STL容器: container<int> c; 现在要删除其中所有值为2012的元素
如果是连续内存容器(vector、string、deque):
c.erase(remove(c.begin(), c.end(), ), c.end()); //erase-remove是删除特定值的最好办法
如果是list容器:
c.remove(c.begin(), c.end(), );//remove是list容器删除特定值的最好办法
如果是标准关联容器(set、map):
c.erase();//erase是set、map容器删除特定值的最好办法(无remove成员函数)
对于 vector、string、deque、list 删除满足条件的特定值时,采用 remove_if
而对于关联容器,比如set容器:写一个循环遍历容器中的元素
std::set<int> c;
for (auto it = c.begin(); it != c.end(); ++it) {
if (func(*it)) c.erase(it);//错误!! 如果erase(*it)之后,位于it之后的所有迭代器全部失效,而循环变量it不能被递增
}
正确写法:
for (auto it = c.begin(); it != c.end(); ) {
if (func(*it)) {
c.erase(it++);
} else {
++it;
}
}
条款10:了解分配子(allocator)的约定和限制
条款11:理解自定义分配子的合理用法
条款12:切勿对STL容器的线程安全性有不切实际的依赖
vector<int> vec; //第1行
vector<int>::iterator it(find(vec.begin(), vec.end(), )); //第2行
if (it != vec.end()) *it = ; //第3行
在多线程环境中,可能在第1行刚刚完成之后,另一个不同的线程会更改vec(扩充重分配内存),这样导致 it 迭代器失效,对it解引用错误
此时应该对这3行代码块进行手工同步控制,引入互斥锁(以对象管理锁资源)
STL学习笔记(一) 容器的更多相关文章
- STL学习笔记— —无序容器(Unordered Container)
简单介绍 在头文件<unordered_set>和<unordered_map> 中定义 namespace std { template <typename T, ty ...
- STL学习笔记--特殊容器
容器配接器 (1) stack 栈 后进先出(LIFO), 头文件#include<stack> template<class _Ty, class _Container = deq ...
- STL学习笔记--各种容器的运用时机
如何选择最佳的容器类别? 缺省情况下应该使用vector.vector的内部结构简单,并允许随机存取,所以数据的存取十分方便灵活,数据的处理也够快. 如果经常要在序列的头部和尾部安插和移除元素,应采用 ...
- Effective STL 学习笔记 32 ~ 33
Effective STL 学习笔记 32 ~ 33 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记 31:排序算法
Effective STL 学习笔记 31:排序算法 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记 Item 30: 保证目标区间足够大
Effective STL 学习笔记 Item 30: 保证目标区间足够大 */--> div.org-src-container { font-size: 85%; font-family: ...
- Effective STL 学习笔记: Item 22 ~ 24
Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...
- Effective STL 学习笔记 Item 21:Comparison Function 相关
Effective STL 学习笔记 Item 21:Comparison Function 相关 */--> div.org-src-container { font-size: 85%; f ...
- Effective STL 学习笔记:19 ~ 20
Effective STL 学习笔记:19 ~ 20 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
随机推荐
- 讲课笔记3——浮动、margin失效的问题、默认样式重置
EO:搜索引擎优化,一般在网页里面只写一个h1标签,搜索引擎可以通过该h1标签里面的内容搜索你所写的网页(a标签和img标签最好写上title属性)标准写法: .logo { text-decorat ...
- VM虚拟机下的Linux不能上网
虚拟机linux上网配置 图解教程 首先查看window7主机下的网络配置VMNet1或VMNet8是否开启,其实linux系统的网络连接跟linux系统一致 在虚拟机界面将桥接改为NAT连接 点虚拟 ...
- 如何在Mac上放大
您是否发现有时自己眯眼盯着屏幕,希望屏幕上的东西只是“大”一点?无论您是否视力差,或只是想放大屏幕来看近景,这是很容易做到,只需要按一些按键.这篇文章将告诉您如何放大看浏览器或桌面的特写. 方法 ...
- PJSIP-iOS源码编译
官方文档https://trac.pjsip.org/repos/wiki/Getting-Started/iPhone 功能 在iPhone上可以实现的功能: 包含基于CoreAudio的音频设备, ...
- java面试基础篇(二)
上一篇,我们说了一下线程和Map,或许那些太抽象,不太好理解,也不太方便记忆,我们这次说一些简单的. 1.Q:java的基本数据类型有哪些? A:四种整数类型(byte.short.int.long) ...
- 《零基础入门学习Python》【第一版】视频课后答案第003讲
测试题答案: 0. 以下哪个变量的命名不正确?为什么? (A) MM_520 (B) _MM520_ (C) 520_MM (D) _520_MM(C)选项不正确,因为 Python 中的变量名不能以 ...
- Day06for循环和字符串的内置方法
Day06 1.for循环(迭代器循环) while循环 条件循环,循环是否结束取决于条件的真假 for循环,迭代器循环,多用于循环取值,循环是否结束取决于被循环数据的元素个数 2.range(1,5 ...
- Java基础知识:集合框架
*本文是最近学习到的知识的记录以及分享,算不上原创. *参考文献见链接. 目录 集合框架 Collection接口 Map接口 集合的工具类 这篇文章只大致回顾一下Java的总体框架. 集合框架 ht ...
- python中os模块讲解
本文主要介绍一些os模块常用的方法: 先看下我的文件目录结构 D:\LearnTool\pycode\part1 在此目录下的文件如下: abcd.py demo1.1.py demo1.2.py z ...
- 常见slave 延迟原因以及解决方法
一 序言在运维线上M-M 架构的MySQL数据库时,接收的比较多关于主备延时的报警: 点击(此处)折叠或打开 check_ins_slave_lag (err_cnt:1)critical-slav ...