43-C++数组的替代品vector和array

4.10 数组的替代品

本章前面说过,模板类vector和array是数组的替代品。下面简要地介绍它们的用法以及使用它们带来的一些好处。

4.10.1 模板类vector

模板类vector类似于string类,也是一种动态数组,您可以在运行阶段设置vector对象的长度,可在末尾附加新数据,还可在中间插入新数据。基本上,它是使用new创建动态数组的替代品。实际上,vector类确实使用new和delete来管理呢额IC,但这种工作是自动完成的。

这里不深入探讨模板类意味着什么,而只介绍一些基本的实用知识。首先,要使用vector对象,必须包含头文件vector,其次,vector包含在名称空间std中,因此您可使用using编译指令、using声明或std::vector。第三,模板使用不同的语法来指出它存储的数据类型。第四,vector类使用不同的语法来指定元素数。下面是一些示例:

#include <vector>

...

using namespace std;

vector<int> vi;

int n;

cin>>n;

vector<double>vd(n);

其中,vi是一个vector<int>对象,vd是一个vector<double>对象。由于vector对象在您插入或添加值时自动调整长度,因此可以将vi的初始长度设置为零。但要调整长度,需要使用vector包中的各种方法。

一般而言,下面的声明创建一个名为vt的vector对象,它可存储n_elem个类型为typeName的元素:

vector<typeName> vt(n_elem);

其中参数n_elem可以是整型常量,也可以是整型变量。

4.10.2 模板类array(C++11)

vector类的功能比数组强大,但付出的代价是效率稍低,如果您需要的是长度固定的数组,使用数组更是最佳的现在,但代价是不那么方便和安全。有鉴于此,C++11新增了模板类array,它也位于名称空间std中。与数组一样,array对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便、更安全。要创建array对象,需要包含头文件array。array对象的创建语法与vector稍有不同:

#include <array>

...

using namespace std;

array<int ,5> ai;

array<double ,4> ad = {1.2 , 2.1 , 3.43 , 4.3};

推而广之,下面的声明创建一个名为arr的array对象,它包含n_elem个类型为typename的元素:

array<typename , n_elem> arr;

与创建vector对象不同的是,n_elem不能是变量。

C++11中,可将列表初始化用于vector和array对象,但在C++98中,不能对vector对象这样做。

4.10.3 比较数组、vector对象和array对象

要了解数组、vector对象和array对象的相似和不同之处,最简单的方法可能是看一个使用它们的简单示例,如程序4.24所示。(楼楼编译器不支持数组的替代品)

//choices.cpp——array variations
#include<iostream>
#include<vector>
#include<array>

int main()
{	
	using namespace std;	
	double a1[4] = {1.2 , 2.4, 3.6, 4.6};
	vector<double> a2(4);
	a2[0] = 1.0/3.0;
	a2[1] = 1.0/5.0;
	a2[2] = 1.0/7.0;
	a2[3] = 1.0/9.0;
	array<double , 4> a3 = {3.14,2.72,1.62,1.41};
	array<double , 4> a4;
	a4=a3;
	cout<<"a1[2]: "<<a1[2]<<" at "<<&a1[2]<<endl;
	cout<<"a2[2]: "<<a2[2]<<" at "<<&a2[2]<<endl;
	cout<<"a3[2]: "<<a3[2]<<" at "<<&a3[2]<<endl;
	cout<<"a4[2]: "<<a4[2]<<" at "<<&a4[2]<<endl;
	a1[-2] = 20.2;
	cout<<"a1[-2]: "<<a1[-2]<<" at "<<&a1[-2]<<endl;
	cout<<"a3[2]: "<<a3[2]<<" at "<<&a3[2]<<endl;
	cout<<"a4[2]: "<<a4[2]<<" at "<<&a4[2]<<endl;
	return 0;
}

下面是该程序的输出示例:

a1[2] : 3.6 at 0x28cce8

a2[2] : 0.142857 at 0xca0328

a3[2] : 1.62 at 0x28ccc8

a4[2] : 1.62 at 0x28cca8

a1[-2] : 20.2 at 0x28ccc8

a3[2] : 20.2 at 0x28ccc8

a4[2] : 1.62 at 0x28cca8

程序说明

首先,注意到无论是数组、vector对象还是array对象,都可使用标准数组表示法来访问各个元素。其次,从地址可知,array对象和数组存储在相同的内存区域(即栈)中,而vector对象存储在另一个区域(自由存储区或栈)中,第三,注意到可以将一个array对象;而对于数组,必须逐元素复制数据。

接下来,下面一行代码需要特别注意:

a1[-2] = 20.2;

索引-2是什么意思呢?本章前面说过,这将被转换为如下代码:

*(a1 - 2) = 20.2;

其含义如下:找到a1指向的地方,向前移两个double元素,并将20.2存储到目的地。也就是说,将信息存储到数组的外面。与C语言一样,C++也不检查这种超界错误。在这个示例中,这个为止位于array对象a3中。其他编译器可能将20.2放在a4中,甚至做出更糟糕的选择。这表明数组的行为是不安全的。

vector和array对象能够禁止这种行为吗?如果您让它们禁止,它们就能禁止。也就是说,您仍可编写不安全的代码,如下所示:

a2[-2] = .5;

a3[200] = 1.4;

然而,您还有其他选择。一种选择是使用成员函数at()。就像可以使用cin对象的成员函数getline()一样,您也可以使用vector和array对象的成员函数at():

a2.at(1) = 2.3 ;

中括号表示法和成员函数at()的差别在于,使用at()时,将在运行期间捕获非法索引,而程序默认将中断。这种额外检查的代价是运行时间更长,这就是C++让允许您使用任何一种表示法的原因所在。另外,这些类还让您能够降低意外超界错误的概率。例如,它们包含成员函数begin()和end(),让您能够确定边界,以免无意间超界,这将在第16章讨论。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值