2.3、std::array(固定大小数组容器)

什么是std::array?用大白话说

你平时写C++代码,可能会用类似int arr[10];这样的传统数组。它很快,但有几个“坑”:

  • • 它不知道自己有多大,传给函数时会退化成指针,导致无法安全获取长度。
  • • 访问越界不会报错,容易引发难查的bug。
  • • 它没有成员函数,不能用现代C++的容器接口。

std::array就是为了解决这些问题而生的。它是一个模板类,固定大小,大小在编译时确定,内部就是包了一层传统数组,但提供了更安全、更丰富的操作接口。它不会退化成指针,知道自己的大小,访问越界时还能抛异常(at()方法),用起来更放心。

设计哲学:安全、固定、兼容

std::array的设计哲学可以总结为:

  • • 安全第一:避免C数组的隐式指针退化,防止越界访问,提供边界检查。
  • • 固定大小:大小在编译时确定,保证效率和内存连续性,适合对大小有严格要求的场景。
  • • 标准容器接口:支持迭代器、size()empty()front()back()等接口,和STL算法无缝集成。
  • • 轻量无开销:本质上就是包了一层数组,性能几乎和C数组一样,没有动态内存分配。

代码对比:传统数组 vs std::array

#include <iostream>
#include <array>

void printCArray(int* arr, size_t size) {
    for(size_t i = 0; i < size; ++i)
        std::cout << arr[i] << " ";
    std::cout << "\n";
}

void printStdArray(const std::array<int5>& arr) {
    for(auto elem : arr)
        std::cout << elem << " ";
    std::cout << "\n";
}

int main() {
    // 传统C数组
    int cArr[5] = {12345};
    printCArray(cArr, 5); // 需要手动传大小,容易传错

    // std::array
    std::array<int, 5> stdArr = {12345};
    printStdArray(stdArr); // 不用传大小,安全方便

    // 越界访问示例
    // std::cout << cArr[10] << "\n"; // 未定义行为,可能崩溃或输出垃圾
    try {
        std::cout << stdArr.at(10) << "\n"// 抛出异常,安全提示
    } catch (const std::out_of_range& e) {
        std::cout << "异常捕获:" << e.what() << "\n";
    }

    return 0;
}

对比解析:

传统数组需要手动传递大小,容易出错,且访问越界不会报错。
std::array自带size(),访问越界用at()会抛异常,安全得多。
std::array支持范围for循环,接口更现代。

使用场景和优缺点

适合用std::array的场景:

  • • 大小固定且已知:比如存储一周7天的温度,或固定维度的向量。
  • • 对性能有要求:栈上分配,连续内存,访问速度快。
  • • 需要和STL算法配合:std::array直接支持迭代器,方便调用std::sortstd::find等。
  • • 希望代码更安全:防止越界,避免指针退化带来的隐患。

优点总结

  • • 安全性高:防止隐式指针退化,at()带边界检查。
  • • 接口丰富:支持size()empty()、迭代器等标准容器接口。
  • • 性能接近C数组:无动态分配,内存连续。
  • • 易于复制和赋值:重载了拷贝构造和赋值运算符。

缺点和限制

  • • 大小固定:不能动态扩展,灵活性不如std::vector
  • • 初始化稍繁琐:二维数组声明比C数组更冗长。
  • • 需要包含头文件:相比C数组多了依赖。
  • • 越界检查开销:at()有边界检查,release模式下可能被优化掉,debug模式下有性能损失。

错误使用后果

  • • 误用operator[]越界访问:仍然是未定义行为,可能导致程序崩溃或数据错误。
  • • 误以为std::array可以动态扩容:它是固定大小容器,不能push_backresize,误用会导致编译错误或逻辑错误。
  • • 忽略异常捕获:使用at()访问时不捕获异常,程序可能异常终止。
  • • 滥用二维std::array导致代码臃肿:二维或多维数组声明复杂,影响代码可读性。

总结

std::array是C++11对传统数组的现代化升级,设计上追求安全、固定和标准化,适合固定大小、对性能和安全有要求的场景。它弥补了C数组的缺陷,提供了更丰富的接口和更强的类型安全,且性能几乎无损。理解并合理使用std::array,能让你的C++代码更健壮、更现代。

不过,std::array不是万能的,面对动态大小需求时,还是得用std::vector。在实际项目中,std::array适合用作固定大小的缓冲区、配置参数容器、数学向量等,避免了裸数组的隐患,提升代码质量。

本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)

阅读剩余
THE END