array
std::array 是 C++11 引入的定长顺序容器,可以把它理解为“更现代、接口更完整的原生数组包装”。它的元素个数在编译期就固定下来,既保留了连续内存布局,又提供了 STL 风格的成员函数和迭代器接口。
和原生数组 int arr[5] 相比,std::array 更适合放进泛型代码和标准算法中,因为它知道自己的长度,并且可以直接调用 size()、begin()、end() 这类接口。
头文件与基本特征
使用 array 时,需要包含:
#include <array>
常见特征如下:
| 特征 | 说明 |
|---|---|
| 长度 | 固定,模板参数里指定 |
| 内存布局 | 连续存储 |
| 随机访问 | 支持 |
| 元素数量变化 | 不支持增删,长度不可变 |
| 适配 STL 算法 | 很好,支持迭代器接口 |
std::array<T, N> 中,T 是元素类型,N 是元素个数。例如:
std::array<int, 4> nums;
这表示一个拥有 4 个 int 元素的定长容器。
基本用法
#include <array>
#include <iostream>
int main() {
std::array<int, 4> nums = {10, 20, 30, 40};
std::cout << nums[0] << '\n';
std::cout << nums.size() << '\n';
return 0;
}
这里的 nums 看起来像普通数组,但它本质上是一个对象,因此可以调用成员函数。
交互演示(MDX + React)
下面这个小面板用来演示 std::array 的几个核心特征:长度固定、支持随机访问、at() 会做边界检查,以及 fill()、swap() 会如何影响整体状态。
std::array 定长行为演示
观察随机访问、at() 边界检查、fill() 全量赋值以及 swap() 交换内容时的状态变化。
[3, 6, 9, 12]
[100, 200, 300, 400]
固定长度 = 4,当前选中 arrayA[0] = 3
最近操作
- 初始化: arrayA = [3, 6, 9, 12]
说明:这个交互示例是教学用的状态模拟,不是执行真实 C++ 代码;它的目的是帮助理解 std::array 的接口行为和“定长容器”这个概念。
访问元素
std::array 支持多种访问方式:
#include <array>
#include <iostream>
int main() {
std::array<int, 3> nums = {1, 2, 3};
std::cout << nums[0] << '\n';
std::cout << nums.at(1) << '\n';
std::cout << nums.front() << '\n';
std::cout << nums.back() << '\n';
return 0;
}
它们的区别可以简单理解为:
operator[]速度直接,不做边界检查。at()会做边界检查,越界时抛出异常。front()返回首元素。back()返回尾元素。
如果你不确定下标是否安全,at() 通常更稳妥。
遍历 array
std::array 可以像其它 STL 容器一样遍历:
#include <array>
#include <iostream>
int main() {
std::array<int, 4> nums = {2, 4, 6, 8};
for (std::array<int, 4>::iterator it = nums.begin(); it != nums.end(); ++it) {
std::cout << *it << ' ';
}
std::cout << '\n';
return 0;
}
也可以直接配合范围 for:
for (int value : nums) {
std::cout << value << ' ';
}
因为底层是连续内存,std::array 在遍历和随机访问上都很自然。
常用成员函数
| 函数 | 作用 |
|---|---|
size() | 返回元素个数 |
empty() | 判断是否为空 |
begin() / end() | 获取迭代器 |
front() / back() | 访问首尾元素 |
at(pos) | 带边界检查地访问元素 |
fill(value) | 把所有元素设为同一个值 |
swap(other) | 与另一个同类型 array 交换内容 |
data() | 获取底层首元素指针 |
虽然它叫“容器”,但不像 vector 那样支持 push_back()、insert()、erase()。原因很简单:长度从一开始就是固定的。
fill 与 swap
fill() 和 swap() 是 std::array 很常用的两个接口。
#include <array>
int main() {
std::array<int, 4> a = {1, 2, 3, 4};
std::array<int, 4> b = {10, 20, 30, 40};
a.fill(7); // a -> {7, 7, 7, 7}
a.swap(b); // a 和 b 交换内容
return 0;
}
fill() 很适合做统一初始化;swap() 则适合快速交换两个等长数组对象。
与原生数组配合
std::array 仍然保持了连续内存,因此可以通过 data() 拿到底层指针:
#include <array>
void printFirst(const int* p) {
if (p) {
// ...
}
}
int main() {
std::array<int, 3> nums = {1, 2, 3};
printFirst(nums.data());
return 0;
}
这让 std::array 在保留“像数组一样存储”的同时,又比原生数组更容易参与现代 C++ 代码组织。
作为函数参数
因为 std::array 的长度是类型的一部分,所以不同长度是不同类型:
#include <array>
#include <iostream>
void printArray(const std::array<int, 3>& nums) {
for (std::size_t i = 0; i < nums.size(); ++i) {
std::cout << nums[i] << ' ';
}
std::cout << '\n';
}
int main() {
std::array<int, 3> nums = {1, 2, 3};
printArray(nums);
return 0;
}
std::array<int, 3> 和 std::array<int, 5> 不是同一个类型,这一点在模板和函数传参时要特别注意。
array、原生数组、vector 如何选择
可以这样快速判断:
- 元素个数编译期已知,而且不需要扩容:优先
std::array。 - 只是在很底层、很简单的场景里临时使用固定数组:原生数组也能用,但接口能力更弱。
- 元素个数运行期才知道,或者后续要增删扩容:选择
std::vector。 - 想要连续内存,同时希望有
size()、迭代器、算法适配能力:std::array往往是更现代的固定长度选择。
使用注意
std::array长度固定,不能push_back()。- 模板参数里的长度也是类型一部分,不同长度不能混用。
operator[]不检查越界,at()才会检查。- 它是对象而不是裸数组,赋值、拷贝、比较都更自然。
- 想要可变长容器时,不要勉强用
std::array,直接用vector更合适。
小结
std::array 很适合“长度固定、需要连续内存、又想使用 STL 风格接口”的场景。它可以看作是原生数组和标准容器风格之间的一座桥:既轻量,又规整。掌握 size、at、fill、swap、迭代器这些基础接口后,就能覆盖绝大多数 std::array 的日常用法。