文章

array

std::array 是固定大小的数组封装,支持 STL 接口,内存连续且分配在栈上,适合大小已知且不变的数据存储。

array

array

std::array 是 C++11 引入的固定大小数组封装类,本质就是对原生数组 T[N] 的安全封装,提供了 STL 容器的接口支持(如迭代器、begin()size()fill()等)。

适合在栈上存储、大小已知的固定数组,功能强于 C 风格数组,效率接近裸数组。

基本语法与使用

1
2
3
4
5
6
7
#include <array>

std::array<int, 5> arr = {1, 2, 3, 4, 5};
arr[0] = 10;
arr.at(1) = 20;
arr.size();           // == 5
arr.fill(0);          // 全部置为 0

底层实现原理

1
2
3
4
5
template<typename T, std::size_t N>
struct array {
    T elems[N];  // 本质就是原生数组
    ...
};
  • 固定大小N 是模板参数,编译时决定
  • 栈上分配:不像 vector 使用堆内存
  • 内存连续:与 T[N] 一样,可与 C 接口兼容
  • 无扩容能力:只能用于固定数量元素的场景

常用接口

接口功能
at(i)越界检查访问
operator[]快速访问
front() / back()首/尾元素
size()返回元素数量(编译期常量)
fill(val)全部赋值为 val
begin() / end()STL 迭代器支持
data()返回底层 T* 指针
1
2
for (int x : arr) {}
std::sort(arr.begin(), arr.end());

与其他容器对比

容器是否定长是否可扩容是否连续内存是否支持 STL 算法
array
vector
list❌(链式)
C 数组 T[]❌(无接口)

典型场景

固定大小的缓存、结构体字段

1
2
std::array<uint8_t, 16> uuid;
std::array<char, 128> buffer;

与 C 接口交互

1
2
3
void foo(char* buf);
std::array<char, 128> buffer;
foo(buffer.data());

注意事项

不能 resize

1
arr.resize(10); // 编译错误

不能推导长度

1
std::array a = {1,2,3}; // 错误,必须写明长度

必须这样写:

1
std::array<int, 3> a = {1, 2, 3};

(C++20 支持 std::to_array() 自动推导)

和 C 数组区别

特性T[N]std::array<T,N>
默认初始化✅(值初始化或空)
拷贝赋值
成员函数✅(fill, size 等)
支持 STL 算法
传参变指针✅(退化)❌(保持类型)

对于原生数组 int arr[3];,不能直接用赋值操作或拷贝构造:

1
2
3
int arr1[3] = {1,2,3};
int arr2[3];
arr2 = arr1;  // 编译错误,数组不支持赋值操作

std::array 是一个封装类,支持默认的拷贝构造和赋值运算符:

1
2
3
std::array<int, 3> a = {1,2,3};
std::array<int, 3> b;
b = a;          // 元素逐个拷贝

std::array vs std::vector 使用场景选择

特性/场景std::arraystd::vector
大小是否固定✅ 固定,编译期确定大小❌ 动态,可运行时调整大小
内存分配栈上分配(或内嵌对象内存)堆上分配,动态管理
性能高,连续内存,无堆开销稍低,可能有扩容和堆分配开销
安全性较高,支持 .at() 越界检查较高,支持 .at() 越界检查
是否支持动态扩容❌ 不支持✅ 支持
适合场景- 元素数量固定 - 小数组或嵌套数组 - 性能敏感的栈空间操作- 元素数量不固定 - 需要频繁插入删除 - 容器大小动态变化
使用方便程度简单,接口少丰富,功能强大
迭代器稳定性永远有效可能失效(扩容、插入、删除)
与 C 接口兼容性高,直接可获取指针,且指针有效期稳定高,但需注意扩容导致地址变化
示例std::array<int, 4> a = {1,2,3,4};std::vector<int> v = {1,2,3,4};

何时选用 std::array

  • 元素数量固定且已知,编译期大小确定。
  • 需要最高性能,避免堆分配和内存碎片。
  • 作为类成员,方便拷贝和赋值。
  • 用于小型缓存、固定格式数据(如颜色通道、坐标点)。
  • 需要和 C 接口无缝兼容。

何时选用 std::vector

  • 元素数量不确定或动态变化。
  • 需要频繁插入、删除或调整大小。
  • 容器大小大或数据量庞大,堆分配更灵活。
  • 希望利用丰富的 STL 算法和适配器。
  • 需要可变长度数组行为。

额外建议

  • 对于性能极限场景,优先考虑 std::array,避免堆分配。
  • 不确定大小时,用 std::vector
  • C++20 以后可用 std::span 作为 arrayvector 共享的轻量视图,避免拷贝。

作为类成员 / 模板参数

1
2
3
struct Packet {
    std::array<uint8_t, 256> data;
};

或者传入函数:

1
2
3
4
template<std::size_t N>
void print(const std::array<int, N>& arr) {
    for (auto x : arr) std::cout << x << " ";
}
本文由作者按照 CC BY 4.0 进行授权