您的位置:首页 > 编程语言 > C语言/C++

《C++ primer》英文第五版阅读笔记(十)——vector类型

2015-11-06 14:11 330 查看
Chapter2.Section3.3——library vector Type

vector类型

vector是许多对象的集合,这些对象有着相同的类型。通常把vector当成一个容器,因为它包含了许多对象。

要使用vector,必须要包含合适的头文件:

#include <vector>

using std::vector;

vector是一个类模板。C++有类模板和函数模板。当对C++有着深入的理解时才能写出类模板。

模板不是类或函数。他们可以被认为是编译器生成类或函数的指令。

实例化:编译器从类模板中创建类或函数的过程。

当我们使用一个模板时,我们要给编译器说明我们想要实例化什么样的类或函数。

对于类模板来说,我们通过提供额外的信息来说明要对哪个类进行实例化,其性质取决于类模板。

对额外的信息进行说明时的方式是相同的:我们在模板名字后面的角括号里面提供要说明的信息。

我们在vector里面提供的额外的信息是vector存储的元素的类型。

例:vector<int> ivec; vector<Sales_item> Sales_vec; vector<vector<string>> file;

vector是一个模板,而不是一个类型。vector所生成的类型必须包含元素的类型。例:vector<int> ivec;

我们能用vector来存储大多数类型的对象。由于引用并不是对象,我们不能用vector来存储引用。我们能用vector来存储许多其他(非引用)内置类型和大多数的类类型。有时vectors本身的元素也是vector。

在早期的C++里面,定义vector里的元素是vector或是其他模板类型的语法是不相同的。在以前,我们在vector和元素类型的两个相邻的输出角括号之间加上一个空格——vector<vector<string>
>,而不是现在的 vector<vector<string>>。

有一些编译器可能需要用以前的定义方式来定义元素类型的vector的vector。

(一)定义和初始化vectors

和许多类类型一样,vector模板控制了我们能够怎样定义和初始化vectors。

通常用来定义vectors的方式:

vector<T> v1;vector存储的对象的类型是T,这是默认的初始化方式。v1是空的。

vector<T> v2(v1);v2里面的元素是v1里面每一个元素的复制。

vector<T> v2 = v1;和v2(v1)一样。v2里面的元素是v1里面每一个元素的复制。

vector<T> v3(n,val);v3有n个元素,每一个元素的值都是val。

vector<T> v4(n);v4有n个值初始化对象。

vector<T> v5{a,b,c...};v5有许多初始化了的元素。

vector<T> v5 = {a,b,c...};同v5{a,b,c...}一样。

vector<T>
v1;


我们可以采用默认的方式给vector进行初始化,这时定义了一个指定类型的空的vector。

vectors最常用的方式是定义一个空的vector,在运行时给它添加元素。

可以用列表初始化的方式对vector进行初始化。

C++提供了许多初始化的方式,但是并不是所有形式的初始化都是可交换的。目前为止,我们能够总结出两个初始化形式的特点:1.当我们使用复制初始化的形式时(使用=),我们只能使用一个初始化器。2.当我们使用类内(in-class)初始化方式时,我们必须使用复制初始化或者使用花括号。第三个约束是我们通过许多值的列表进行初始化时只能将元素的值放在花括号里面进行列表初始化,而不能放在小括号里面。

vector<T> v4(n);



这种方式初始化的vector有n个元素,每一个元素采用值初始化的方式,具体的值由vector里面存储的元素类型决定。

这种初始化方式会有两种限制:

1.有些类会要求我们提供一个具体的初始化器时不能采用这种初始化方式。如果我们的vector存储的对象的类型不能够进行默认初始化方式(也就是必须提供具体的值),而vector<T> v4(n);这种初始化方式只能提供一个大小,而不能提供具体的值,所以这种情况下就不能采用这种初始化方式。

2.当只给vector提供大小进行初始化时,只能采用直接初始化方式,不能采用复制初始化方式。

当使用小括号()进行初始化时,通常是当做构造一个对象。

当使用花括号{}进行初始化时,通常是当做列表初始化进行值的初始化。

当花括号里面的值不能被看作是列表初始化的方式对对象进行初始化,那么这些值就被看作是构造一个对象。

例:vector<string> v5{"hi"};//列表初始化

vector<string> v5("hi");//error,不能用字符串literals构造一个vector。

vector<string> v7{10};//v7有10个是默认值的元素

vector<string> v8{10,"hi"};//v8有10个元素,每一个元素的值都是"hi"。

(二)给vector添加元素

有时我们并不知道vector含有多少个元素,每个元素的值是多少。这时就可以定义一个空的vector,然后用vector里面的push_back方法在运行时给vector添加元素。

这种方式通常都是高效。有一个例外:当所有元素的值都是相同的的时候。

但是我们必须要保证我们写的循环是正确的,即使循环改变了vector的大小。

值得注意的是:我们不能在range for的循环体里面给vector添加元素。

range for的主体一定不能改变它所迭代的序列的大小。

(三)其他的vector操作

除了push_back,vector的大多数其他操作都和string类似。

使用vector里面的元素的方式和使用string里面的字符的方式一样:通过使用vector里面元素的位置。

empty操作返回一个bool值,表示vector里面是否含有元素。

size操作返回vector里面含有的元素的个数,它的类型是size_type。

为了使用size_type,我们必须命名它所定义的类型。一个vector类型通常包含它的元素类型。

例:vector<int>::size_type;//ok

vector::size_type;//error

当两个vector的元素个数相同,并且每个元素对应的值也相同时,这两个vector就是相同的。

两个vector比较大小时,按照字典顺序比较,规则和string一样。

当vectors里面的元素可以进行比较大小时,这两个vectors对象才能进行大小比较。

我们可以使用下标的方式vector中的元素。下标从0开始,类型是size_type。如果vector不是const类型的,可以通过下标法改变vector里面元素的值。

在vector和string上使用下标法只能获得已经存在的元素,因此不能用下标法添加元素。

注意:下标法只能取得已经存在的元素,在一个不存在的元素上使用下标是会出错的,但是编译器通常察觉不到这种错误,这种情况下得到的值是undefined。这种错误叫做“缓冲区溢出”。并且通常会引发电脑和应用程序的安全问题。

一个确保下标在合理范围内的方法是在可能的情况下不使用下标,而使用range for。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: