博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
###学习《C++ Primer》- 2
阅读量:4983 次
发布时间:2019-06-12

本文共 4009 字,大约阅读时间需要 13 分钟。

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

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

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

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

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

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

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

二、容器的关系运算符

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

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

三、STL容器使用的是拷贝

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

四、使用emplace_back,emplace,emplace_front

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

vector
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
sv; //空vectorcout << 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
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
il(10, 42);il.resize(15); //在最后加入5个0il.resize(25, -1); //在最后加入10个-1il.resize(5); //删除末尾的20个元素

八、在循环中保持迭代器

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

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

vector
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

转载于:https://www.cnblogs.com/gr-nick/p/4069782.html

你可能感兴趣的文章