变量可扩展性难题
假设我们需要记录 30 名学生的测验分数并计算班级平均分。最直接的做法是定义 30 个独立变量:
// 分配 30 个整型变量(名称各不相同)
int testScore1{};
int testScore2{};
int testScore3{};
// ...
int testScore30{};
随后计算平均分:
int average{ (testScore1 + testScore2 + ... + testScore30) / 30 };
这种写法不仅冗长、重复,而且极易出现编号笔误。若班级新增一名学生,必须到处插入 testScore31
,并手动将除数从 30 改为 31——稍有不慎即会引入 bug。当数据量达到成百上千时,单独命名变量显然无法扩展。
即使把数据放进结构体:
struct testScores
{
int score1{};
int score2{};
// ...
int score30{};
};
也只是把问题封装了一层:仍需逐一命名成员,核心困难依旧存在。
容器(Containers)
现实生活中,我们购买鸡蛋时不会逐个挑选 12 枚蛋,而是直接拿一盒;早餐麦片也不会一粒粒存放,而是整盒存储。这些“盒子”就是容器(container),它们让批量管理物品变得简单。
编程中的容器亦然:它是一种数据类型,用于存储无名元素的集合。
关键洞见:当我们需要处理一组相关值时,通常会使用容器。
你已接触过一种容器——std::string
,它存储字符序列:
std::string name{ "Alex" }; // 字符容器
容器元素无名,因此可容纳任意数量元素而无须逐一命名。
容器通过专用接口访问元素;接口形式因容器类型而异。
容器长度
元素数量常称为长度(length)或计数(count)。std::string
提供 length()
成员函数:
std::cout << name.length(); // 4
C++ 亦用 size 表示元素个数(与 sizeof
字节的含义区分)。
下文统一使用“长度”指元素数量,“大小”指内存占用。
容器操作
如同鸡蛋盒可“取出、放入、计数”,容器通常支持:
- 创建(空、预分配、由值列表);
- 元素访问(首、尾、任意位置);
- 插入与删除;
- 获取长度;
- 其他辅助操作。
不同容器在支持的操作及性能上各有侧重:
- 有的支持随机快速访问,但不擅插入删除;
- 有的插入删除高效,但仅支持顺序访问。
选择合适容器对可维护性与性能至关重要。
元素类型
C++ 容器同质(homogeneous):所有元素类型相同。
多数容器以模板形式实现,用户可用模板实参指定元素类型,避免为每种类型创建新容器。
异质容器(heterogeneous)——允许不同元素类型——多见于脚本语言,如 Python。
C++ 中的容器
容器库(Containers library)是 C++ 标准库中实现常用容器的类集合,亦称容器类(container class)。
标准库明确定义的容器见 cppreference。
C++ 对“容器”定义较窄——仅指容器库中的类类型;其余符合一般概念者称为“伪容器”(pseudo-containers)。
常用容器类:
std::vector
(动态数组)std::array
(固定大小数组)- 其他:链表、队列、集合、映射等,用于特殊场景。
数组(Array)
数组是一种顺序存储容器,元素在内存中连续排列,支持快速随机访问。
C++ 提供三种主要数组形式:
- C-style 数组(语言内置,固定大小,行为怪异且易错)。
std::vector
(C++03 引入,动态大小,功能丰富,最常用)。std::array
(C++11 引入,固定大小,安全替代 C-style 数组)。
后续课程将逐一介绍,并重点讲解 std::vector
。
术语说明
- 容器类(container class):泛指标准库容器。
- 数组(array):泛指所有数组类型,包括跨语言概念。
std::vector
同时属于两者,相关内容均适用。
下一步
下一课将正式引入 std::vector
,用它高效解决开篇“学生分数”问题。
所有容器接口相似,掌握了 std::vector
,再学 std::array
等将事半功倍。
作者附言
准备好了吗?
Let’s goooooooooooooooooooooooooooooooooooooooooooooooo.