点击查看Evernote原文

#@author:       gr
#@date: 2014-10-01
#@email: forgerui@gmail.com

Part 2: STL顺序容器(第9章)

一、标准库array(C++11)

array的大小固定,不能省去,它是容器的一部分。

//保存42个int, 初始1,2,其余40个元素初始为0
array<int, 42> = {1, 2}
//保存24个string
array<string, 24>
array<int, 10>::size_type i; //正确
array<int>::size_type j; //错误,没有大小
//类的话必须有一个默认构造函数
array<Widget, 10> aw;

内置数组不能进行数组赋值,拷贝,array可以。

int digs[10] = {1, 2, 3};
int cpy[10] = digs; //错误,不支持赋值
array<int, 10> dig = {1, 2, 3};
array<int, 10> cp = dig; //正确,可以进行赋值,数组大小要一致

二、容器的关系运算符

只有当元素定义了相应的比较运算符,才可以使用容器的关系运算符。

vector<int> v1 = {1, 3, 7};             //初始列,C++11
vector<int> v2 = {1, 3, 7, 9};
v1 < v2 //true,所有元素相等,v1数目更少

三、STL容器使用的是拷贝

用一个对象初始化容器,是将该对象的拷贝放进容器中的,容器中的元素修改与原来的对象没有任何影响。

四、使用emplace_back,emplace,emplace_front

emplace可以直接在内存中创建对象,并且效率更高。

vector<Sales_data> c;
//直接在空间创建对象,节省开销
c.emplace_back("123", 25, 25.99);
//编译错误,没有3个参数的构造
c.push_back("123", 25, 25.99);
//构造临时对象,拷贝进入容器,销毁对象
c.push_back(Sales_data("123", 25, 25.99));

五、容器的访问成员函数

可以使用front,back进行直接访问,也可以通过迭代器进行解引用,获取元素,但在进行访问之前,最好要检测容器是否为空,如果为空,将会产生不确定行为。

对提供了随机访问的容器可以使用下标访问(如v[0]),list则不存在下标访问。下标访问返回的是元素的引用,对其赋值可以直接修改容器中元素的值。下标运算不检查是否在合法范围内,下标越界是一种严重的错误,会导致runtime error。也可以使用at成员函数,如果下标越界,at会抛出一个out_of_range异常。

vector<string> sv;      //空vector
cout << sv[0]; //运行时错误
cout << sv.at(0); //抛出一个out_of_range

六、容器的删除操作

forward_list没有pop_back函数,vectorstring没有pop_front操作。erase(p);删除迭代器p所指定的元素,erase(p, q);删除迭代器p到q范围的元素。在删除之前,必须保证元素是存在的。

forward_list的删除需要两个迭代器,一个是正在处理元素的,一个是前驱元素的迭代器。

//删除容器中的奇数
forward_list<int> flst = {0, 1, 2, 3, 4, 5, 6, 7};
auto prev = flst.before_begin(); //表示flst的“首前元素”
auto curr = flst.begin();
while (curr != flst.end()) {
if (*curr % 2){ //元素为奇数
curr = flst.erase_after(prev); //删除它并移动curr
}else{
prev = curr;
curr++;
}
}

七、改变容器的大小

使用resize来改变容器的大小,array不支持resize。如果当前大小大于所要求的大小,容器后部的元素会被删除;如果当前大小小于要求的大小,将新元素加入到容器中。

list<int> il(10, 42);
il.resize(15); //在最后加入5个0
il.resize(25, -1); //在最后加入10个-1
il.resize(5); //删除末尾的20个元素

八、在循环中保持迭代器

容器的操作可能会使已有的迭代器失效,如何在循环过程中保持这些迭代器,以使整个循环过程正确?

办法是使用成员函数操作的返回值更新迭代器,虽然list的某些操作并不影响迭代器,但为了统一,最好所有的顺序容器都使用相同的形式。

vector<int> vi = {1, 2, 3, 4, 5};
auto iter = vi.begin();
iter = vi.insert(iter, 2); //用insert返回值更新迭代器
iter = vi.erase(iter); //删除元素

九、不要试图保存end返回的迭代器

容器的操作会改变end()返回的迭代器,所以不要保存它。这也是为什么在循环中,为何反复调用v.end()进行判断是否结束。

it = v.begin();
while (it != v.end()){ //反复调用v.end()检查
//...
}

十、理解vector是如何增长的

capacity表示容量,是已经申请的内存空间,size是已经保存的元素的数目。

使用reserve改变容器的容量,resize改变容器的大小。

vector内存不够用的时候,会把整个vector复制到更大的内存空间中,造成开销变大。

使用reserve事先申请大的空间,可以避免vector的拷贝,但如果容量过大,则会浪费。

《Effective STL》中的Topic17里面讲解使用"swap技巧"去除多余的容量,实际上,C++11中提供了shrink_to_fit函数来退回不需要的内存空间。

十一、string独有的一些操作

使用string进行字符串处理,可以极大地简化我们的工作。

  1. 一般程序设计语言,都会提供substr函数进行字符串截取。

     //pos开始位置,n截取的个数
    s.substr(pos, n);
  2. insert, erase基于下标版本

    string提供了基于下标版本的成员函数。

     s.insert(s.size(), 5, '!');     //在最后插入5个!
    s.erase(s.size()-5, 5); //删除最后5个元素
  3. append,replace

     string s("C++ Primer"), s2 = s;
    s.insert(s.size(), " 4th Ed."); //追加
    s.append(" 4th Ed."); //等价上面insert方法

    replaceeraseinsert操作的简写:

    s.erase(11, 3);

    s.insert(11, "5th");

    s2.replace(11, 3, "5th"); //等价于上面两句

    s2.replace(11, 3, "Fifth"); //删除3个字符,添加5个也是可以的

  4. 搜索操作

    string一共有6种搜索操作,分别是find, rfind, find_first_of, find_first_not_of, find_last, find_last_not_of。这些都是大小写敏感,返回第一个匹配出现的位置。

     string name("AnnaBelle");
    name.find("Anna"); //返回0
    //使用find_first_of查找在list_c字符出现的第一个位置
    string list_c("cnl");
    name.find_first_of(list_c); //返回1,即n第一次出现的地方
  5. 数值转换

     int i = 42;
    string s = to_string(i); //将i转换为字符表示形式
    double d = stod(s); //将string转换为浮点数

十二、容器适配器

适配器是一种机器,接受一种已有的容器类型,对其改造,使其行为看起来像一种不同的类型。我们定义了适配器,就只能使用适配器提供的操作,不能使用底层容器的操作。

stack栈适配器可以使用vector,deque,list实现;queue可以使用deque,list实现,因为vector没有pop_front

最新文章

  1. [算法]——归并排序(Merge Sort)
  2. 【原】浅谈KL散度(相对熵)在用户画像中的应用
  3. C# 的一些语法特性
  4. Object.prototype 与 Function.prototype 与 instanceof 运算符
  5. c++中的内存空间不足和自定义处理内存不足
  6. 使用call来实现继承
  7. 最近这么火的iOS视频直播
  8. iOS开发——多线程篇——NSThread
  9. 用Java通过串口发送手机短信
  10. hdu 5265 pog loves szh II STL
  11. I.MX6 bq27441 driver hacking
  12. Linux学习,在线版
  13. JavaScript小知识点(一)
  14. Android 自定义通用的loadingview
  15. 积分图实现均值滤波的CUDA代码
  16. Ubuntu ROS Arduino Gazebo学习镜像iso说明(indigo版)
  17. js 格林威治时间转正常格式并兼容ios
  18. vue插槽,也就是子页面、父页面相互传值的另一写法
  19. 关于Unity中NGUI的Pivot和锚点
  20. SQLUnit 环境搭建

热门文章

  1. [OC Foundation框架 - 7] NSArray的创建与遍历
  2. IsPostBack
  3. Clarkson不等式
  4. iOS开发-表视图的使用
  5. cocos2d-x 判断点击命中坐标的几种方法
  6. cocos2d-x之蒙板,局部高亮可点,CCRenderTexture
  7. UIWebView 获取html标题
  8. 【47】请使用traits classes表现类型信息
  9. OpenCV快速遍历矩阵元素方法
  10. material-design-library