C++标准库类型vector

来源:互联网 发布:数据比对公式vlookup 编辑:程序博客网 时间:2024/05/18 00:44

标准库类型vector表示对象的集合,集合中的每个对象都有一个与之对应的索引用于访问对象,所以常被称作容器(container)。使用如下声明以使用vector:

#include <vector>using std::vector;

C++既有类模板也有函数模板,vector是一个类模板。编译器根据模板创建类或者函数的过程称为实例化( instantiation),当使用模板时,需要指出编译器应把函数或者类实例化为何种类型。
对于类模板,需要提供一些额外信息,如下:

vector<int> ivec;vector<string> svec;vector<vector<string>> file;

vector能容纳绝大多数类型的对象作为其元素,但由于引用不是对象,所以不存在包含引用的vector,绝大多数内置类型或者类类型都可构成vector对象,甚至组成vector的元素也可以是vector。
早起版本的C++中,如果组成vector的元素还是vector或者其他模板类型,则其定义与C++11新标准有些不同。过去的定义方式必须在外层vector的右尖括号与其元素类型之间加一个空格,如:

vector<vector<string> > file;

定义和初始化

有如下几种方式定义和初始化vector:

vector<T> v1;                   //默认初始化,v1不含任何元素vector<T> v2(v1);               //v2中包含v1中所有元素的副本vector<T> v2 = v1;              //与上相同vector<T> v3(n, val);           //包含n个重复的元素,每个元素的值都是valvector<T> v4(n);                //包含了n个地执行了值初始化的对象vector<T> v5{a, b, c};          //列表初始化,包含了初始值个数的元素,每个元素被赋予相应的初始值vector<T> v6={a, b, c};         //与上相同

允许把一个vector对象拷贝给另外一个vector对象,此时,新vector对象的元素就是原vector对象对应元素的副本,但是两个vector对象的类型必须相同。
如果提供的是初始值元素的列表,则只能把初始值都放在花括号里面进行初始化,而不能放在圆括号里面:

vector<string> v1{"a", "bb", "ccc"};        //正确vector<string> v1("a", "bb", "ccc");        //错误

如果只提供元素数量而略去初始值,此时,库会创建一个值初始化的元素初值,并把它赋给容器中所有的元素。如vector对象的元素类型是内置类型,比如int则元素初始值自动设为0,如果是某种类类型,则元素由类默认初始化。如果vector对象中的元素的类型不支持默认初始化,就必须提供初始元素值,对于该种类型的对象来说,只提供元素数量而不设定初始值无法完成初始化工作。
某些情况下,初始化的真实含义依赖于传递初始值时用的是花括号还是圆括号。如:

vector<int> v1(10);                         //10个元素,每个元素都是0vector<int> v2{10};                         //1个元素,值为10vector<int> v3(10, 1);                      //10个元素,每个元素都是1vector<int> v4{10, 1};                      //2个元素,分别为10和1

如果使用圆括号,可以说提供的值是用来构造(construct)vector对象的。如果用的是花括号,可以表述为想要使用列表初始化(list initialize)该vector对象,即尽可能的把花括号内的值当成是元素初始值的列表来处理,只有在无法进行列表初始化是才会考虑其他初始化方式。
如果使用了花括号的形式但是提供的值又不能用来列表初始化,就要考虑用这样的值来构造vector对象了。如:

vector<string> v1{"hi"};                    //列表初始化vector<string> v2("hi");                    //错误,不可使用字面值字符串构建vector对象vector<string> v3(10);                      //v3有10个默认初始化的元素vector<string> v4{10, "hi"};                //v4有10个值为"hi"的元素

确认无法使用列表初始化之后,编译器会尝试使用默认值初始化vector对象。

添加元素

可以使用push_back函数向vector中添加元素,该函数负责将一个值当成vector对象的尾元素压到vector对象的尾端,如:

vector<int> v2;for (int i = 0; i < 10; ++i) {    v2.push_back(i);}

C++标准要求vector应该能在运行时高效快速的添加元素,在定义vector对象时设定其大小会使其性能更差,只有一种例外,即所有元素值都一样的情况。一旦元素的值有不同,更有效的方法是先定义一个空的vector对象,再在运行时添加具体值。
vector的使用有很多隐含的要求,如:
如果循环体内部包含有向vector对象添加元素的语句,则不能使用范围for循环。范围for循环不应改变其所遍历序列的大小。

其他操作

包括如下一些操作,大致与string的操作类似:

v.empty()               //若v中不含任何元素则判断为真,否则为假v.size()                //返回v中元素的个数v.push_back(t)          //向v的末尾添加元素tv[n]                    //返回v中第n个位置上的元素的引用v1 = v2                 //用v2中元素的拷贝替换v1中的元素v1 = {a,b,c...}         //用列表中元素的拷贝替换v1中的元素v1 == v2                //当且仅当它们的元素数量相同且对应位置的元素值都相同时为真<,<=,>,>=               //按字典序进行比较

访问vector中元素方法与访问string对象中字符的方法差不多,如:

vector<int> v{1,2,3,4,5,6,7,8,9};for (auto &i : v) {    i += 10;}for (auto i : v) {    cout << i << endl;}

vector的empty和size两个函数与string的同名成员功能完全一致,注意size返回vector中元素个数,返回值的类型是由vector定义的size_type类型,如:

vector<int>::size_type          //正确vector::size_type               //错误

要使用size_type需首先指定它是由哪种类型定义的,vector对象的类型总是包含这元素的类型。
关系运算符按照字典顺序进行比较:如果两个vector对象的容量不同,但是相应位置上的元素都一样,则元素较少的vector对象小于元素较多的vector对象;若元素的值有区别,则其大小关系由第一对相异的元素值的大小关系决定。只有当元素的值可以比较时,vector对象才能被比较。
使用下标运算符可以获取到指定的元素,但是不能使用下标形式来添加元素,string对象也是如此。只能对确定已知存在的元素进行下标操作,试图使用下标来访问一个不存在的元素将引发错误,不过这种错误不会被编译器发现,而是在运行时产生一个不可预知的值。缓冲区溢出(buffer overflow)指的就是这类错误。