跳到主要内容
版本:Next

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() 交换内容时的状态变化。

MDX + React
arrayA

[3, 6, 9, 12]

arrayB

[100, 200, 300, 400]

size()4
front() / back()3 / 12
next fill value7

固定长度 = 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;
}

它们的区别可以简单理解为:

  1. operator[] 速度直接,不做边界检查。
  2. at() 会做边界检查,越界时抛出异常。
  3. front() 返回首元素。
  4. 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 如何选择

可以这样快速判断:

  1. 元素个数编译期已知,而且不需要扩容:优先 std::array
  2. 只是在很底层、很简单的场景里临时使用固定数组:原生数组也能用,但接口能力更弱。
  3. 元素个数运行期才知道,或者后续要增删扩容:选择 std::vector
  4. 想要连续内存,同时希望有 size()、迭代器、算法适配能力:std::array 往往是更现代的固定长度选择。

使用注意

  1. std::array 长度固定,不能 push_back()
  2. 模板参数里的长度也是类型一部分,不同长度不能混用。
  3. operator[] 不检查越界,at() 才会检查。
  4. 它是对象而不是裸数组,赋值、拷贝、比较都更自然。
  5. 想要可变长容器时,不要勉强用 std::array,直接用 vector 更合适。

小结

std::array 很适合“长度固定、需要连续内存、又想使用 STL 风格接口”的场景。它可以看作是原生数组和标准容器风格之间的一座桥:既轻量,又规整。掌握 sizeatfillswap、迭代器这些基础接口后,就能覆盖绝大多数 std::array 的日常用法。