- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
4.10 数组的替代品
本章前面说过,模板类 vector 和 array 是数组的替代品。下面简要地介绍它们的用法以及使用它们带来的一些好处。
4.10.1 模板类 vector
模板类 vector 类似于 string 类,也是一种动态数组。您可以在运行阶段设置 vector 对象的长度,可在末尾附加新数据,还可在中间插入新数据。基本上,它是使用 new 创建动态数组的替代品。实际上,vector 类确实使用 new 和 delete 来管理内存,但这种工作是自动完成的。
这里不深入探讨模板类意味着什么,而只介绍一些基本的实用知识。首先,要使用 vector 对象,必须包含头文件 vector。其次,vector 包含在名称空间 std 中,因此您可使用 using 编译指令、using 声明或 std::vector。第三,模板使用不同的语法来指出它存储的数据类型。第四,vector 类使用不同的语法来指定元素数。下面是一些示例:
其中,vi 是一个 vector<int>对象,vd 是一个 vector<double>对象。由于 vector 对象在您插入或添加值时自动调整长度,因此可以将 vi 的初始长度设置为零。但要调整长度,需要使用 vector 包中的各种方法。
一般而言,下面的声明创建一个名为 vt 的 vector 对象,它可存储 n_elem 个类型为 typeName 的元素:
其中参数 n_elem 可以是整型常量,也可以是整型变量。
4.10.2 模板类 array(C++11)
vector 类的功能比数组强大,但付出的代价是效率稍低。如果您需要的是长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。有鉴于此,C++11 新增了模板类 array,它也位于名称空间 std 中。与数组一样,array 对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便,更安全。要创建 array 对象,需要包含头文件 array。array 对象的创建语法与 vector 稍有不同:
推而广之,下面的声明创建一个名为 arr 的 array 对象,它包含 n_elem 个类型为 typename 的元素:
与创建 vector 对象不同的是,n_elem 不能是变量。
在 C++11 中,可将列表初始化用于 vector 和 array 对象,但在 C++98 中,不能对 vector 对象这样做。
4.10.3 比较数组、vector 对象和 array 对象
要了解数组、vector 对象和 array 对象的相似和不同之处,最简单的方式可能是看一个使用它们的简单示例,如程序清单 4.24 所示。
程序清单 4.24 choices.cpp
下面是该程序的输出示例:
程序说明
首先,注意到无论是数组、vector 对象还是 array 对象,都可使用标准数组表示法来访问各个元素。其次,从地址可知,array 对象和数组存储在相同的内存区域(即栈)中,而 vector 对象存储在另一个区域(自由存储区或堆)中。第三,注意到可以将一个 array 对象赋给另一个 array 对象;而对于数组,必须逐元素复制数据。
接下来,下面一行代码需要特别注意:
索引-2 是什么意思呢?本章前面说过,这将被转换为如下代码:
其含义如下:找到 a1 指向的地方,向前移两个 double 元素,并将 20.2 存储到目的地。也就是说,将信息存储到数组的外面。与 C 语言一样,C++也不检查这种超界错误。在这个示例中,这个位置位于 array 对象 a3 中。其他编译器可能将 20.2 放在 a4 中,甚至做出更糟糕的选择。这表明数组的行为是不安全的。
vector 和 array 对象能够禁止这种行为吗?如果您让它们禁止,它们就能禁止。也就是说,您仍可编写不安全的代码,如下所示:
然而,您还有其他选择。一种选择是使用成员函数 at()。就像可以使用 cin 对象的成员函数 getline() 一样,您也可以使用 vector 和 array 对象的成员函数 at():
中括号表示法和成员函数 at() 的差别在于,使用 at() 时,将在运行期间捕获非法索引,而程序默认将中断。这种额外检查的代价是运行时间更长,这就是 C++让允许您使用任何一种表示法的原因所在。另外,这些类还让您能够降低意外超界错误的概率。例如,它们包含成员函数 begin() 和 end(),让您能够确定边界,以免无意间超界,这将在第 16 章讨论。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论