第三章 标准库string、vector、bitset类型 —— 第二节 vector类及其迭代器

来源:互联网 发布:翻墙是否违法 知乎 编辑:程序博客网 时间:2024/04/29 10:14

第三章 标准库string、vector、bitset类型

关于C++的几篇博客,参考人民邮电出版社的《C++ Primer 中文版》一书。

本章着重介绍标准库中的string、vector、bitset类。


第二节 标准库vector类及其迭代器

一、vector基本概念

1、vector是一种容器,是C++容器的一种,是同一种类型对象的集合。

2、vector是一个模板类(class template),每次定义时都需要用尖括号包含模板的指定类型才可以。

3、vector不是一种数据类型,而是一个模板类,vector<int>或者vector<string>的格式才表示一种数据类型。

4、重要概念 —— vector对象是动态增长的,也就是元素是可以动态增删的:

为了方便理解这个动态增长的概念,我们可以拿vector跟数组做比较。

数组:提前定义好所需要的内存空间大小,然后分配空间,然后对仅限于该空间范围内的内存进行读写操作。要想增加新的数组元素,是不可能在原数组上实现的。

vector:为了既保持连续的内存空间,又希望能动态增加元素,vector采用push_back()成员函数来实现。为了便于理解,可以简单直观地理解成:每push_back一次,都是重新开辟相应大小的连续空间,然后赋值。


二、vector对象的定义和初始化

vector类的几种构造函数vector<T> v1默认构造函数输出为空vector<T> v2(v1)将v2初始化为v1的一个副本,二者元素完全相同vector<T> v3(n, i)v3包含n个T类型取值为i的元素vector<T> v4(n)v4含有n个值初始化的元素(初始化值为多少取决于模板的数据类型。如果是int,则初始化为0;如果为string,则按照string类的默认构造函数来初始化,也就是每个元素都初始化为空字符串,依此类推;有些类不存在任何构造函数,那么就要求必须提供元素初始值)


三、vector对象的操作

vector对象的操作v.empty()如果v为空,则返回真v.size()返回元素个数,返回类型为vector<int>::size_typev.push_back( t )在v的末位增加一个值为t的元素v[n]略,n的数据类型也为vector<int>::size_type,另:下标操作不能实现添加元素v1 = v2略v1 == v2略!=, <, <=, >, >=略NOTE:

vector<int>::size_type          // right

vector::size_type                   // wrong


四、迭代器

标准库为每一种容器都定义了相应的迭代器类型。迭代器是一种检查容器内元素并遍历元素的数据类型。任何容器的迭代器都符合这个定义,满足这种属性,虽然不同容器的迭代器之间略有不同。那么问题来了,用下标不是可以直接访问容器元素的吗?干嘛还要定义迭代器这种东东?因为在标准库中,只有少数的容器才支持下标操作,而迭代器却适用于所有容器,也就是它提供了比下标操作更通用的方法。

1、基本定义:

vector<int>::iterator iter;         // 定义一个对应于vector<int>这种类型的容器的迭代器对象,命名为iter。iterator是vector模板类的一个成员。
2、begin和end操作:

简单直观地,可以将iterator理解为可指向容器任意元素的指针。

vector<int> v;vector<int>::iterator iter = v.begin();          // 如果v不为空,则iter指向v的第一个元素iter = v.end();                                                  // 如果v不为空,则iter指向v最后一个元素的下一个,即一个不存在的元素,end()只是为了告诉我们所有元素都已经处理完                                                                          // 如果v为空,则v.begin()和v.end()返回值相同
3、用迭代器访问容器元素:

之所以可以理解迭代器为指针,就在于,迭代器可以通过*操作符实现所指向位置的元素取值。

vector<int>::iterator iter = v.begin();          // iter指向v的第一个元素*iter = 0;                                                          // 将第一个元素的值置为0++iter;                                                              // iter现在指向第二个元素int n = 5iter = iter + n;                                                 // iter由第二个元素改为指向第七个元素vector<int>::iterator iter2 = v.begin();vector<int>::difference_type distance = iter2 - iter;          // 计算两个迭代器的距离时,返回类型应为difference_type(signed类型)

例1:

// 用for循环将容器的每个元素设置为0for(vector<int>::iterator iter = v.begin(); iter!=v.end(); ++iter)      *iter = 0;

4、const_iterator: 元素只读迭代器

例2:

for(vector<int>::const_iterator iter = v.begin(); iter!=v.end(); ++iter)  {      *iter = 0;                                                       // error      std::cout << *iter <<std::endl;                   // ok }
例2总结:const_iterator类型的对象,其本身可以改变,但其指向的元素不可改变。

例3:

const vector<int>::iterator iter = v.begin();*iter = 0;                                                           // ok++iter;                                                               // error
例3总结:要区分const_iterator和const的iterator。与例2相反,const的iterator,其本身不可改变,但其指向的元素可以改变。

5、任何改变容器长度的操作都会使已存在的迭代器失效。究其原因,可以这样理解:我们上面说过容器的空间是动态增长的,当push_back增加新元素进去时,重新开辟新的数量的内存空间,然后把新旧元素都放在新的空间中。这时地址已经发生变化了,如果再用之前定义的迭代器,其指向的空间其实已经被释放掉了,无意义了。

0 0
原创粉丝点击