std::array是栈上布局的原生数组封装,内存布局与T[N]一致,零运行时开销;提供vector风格接口但无指针退化问题;operator[]和data()[i]不越界检查,at()才检查并抛异常。

std::array 本质就是封装好的原生数组
std::array 不是动态分配的容器,它在栈上直接布局,内存布局和 T[N] 完全一致。编译器能把它优化成纯原生数组访问,零运行时开销。但它又提供了 std::vector 那样的接口(size()、data()、范围 for),还能避免裸数组退化为指针的坑。
越界检查只在 at() 成员函数中启用
默认下 operator[] 和 data()[i] 都不做边界检查 —— 这是为了保持和原生数组一样的性能。真要检查,必须显式调用 at(),它会在越界时抛出 std::out_of_range 异常。
-
arr[5]:不检查,越界行为未定义(可能读到垃圾值或崩溃) -
arr.at(5):检查索引,越界则抛std::out_of_range -
arr.front()/arr.back():也不检查,空数组时行为未定义
std::arraya = {1, 2, 3}; // 安全(编译期已知大小) for (size_t i = 0; i < a.size(); ++i) { std::cout << a[i] << " "; // 无检查,快 } // 更安全(运行时兜底) try { std::cout << a.at(5); // 抛异常:basic_string::at: __n (which is 5) >= this->size() (which is 3) } catch (const std::out_of_range& e) { std::cerr << e.what() << "\n"; }
初始化和模板参数必须显式指定大小
std::array 是模板类,第二个模板参数是编译期常量尺寸,不能推导。你不能写 std::array{1,2,3}(C++20 聚合推导不支持 std::array),也不能省略大小。
- ✅ 正确:
std::arraya = {1, 2, 3}; - ✅ 正确:
std::array a = std::array(C++17 后可省略类型,但尺寸仍需显式){1, 2, 3}; - ❌ 错误:
std::array(缺少尺寸)a = {1, 2, 3}; - ❌ 错误:
auto a = {1, 2, 3};(这是std::initializer_list,不是std::array)
传参时别忘了用引用,否则复制整个数组
std::array 是值语义类型,按值传递会复制全部元素。对大数组(比如 std::array)来说,这很昂贵。传参务必用 const 引用。
立即学习“C++免费学习笔记(深入)”;
- ❌ 慢:
void foo(std::arraya) - ✅ 快:
void foo(const std::array& a) - ✅ 通用:
templatevoid foo(const std::array & a)
真正容易被忽略的是:即使你用了 at(),它的检查也只发生在运行时;而编译期越界(比如 std::array 这种字面量索引)无法被编译器捕获 —— 因为 at() 是函数调用,不是 constexpr 检查。想静态断言,得自己加 static_assert(i 或用 std::get(但索引必须是编译期常量)。











