###学习《C++ Primer》- 2

点击查看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

原文地址:https://www.cnblogs.com/gr-nick/p/4069782.html