C++标准模板库(STL)array固定容器

std::array 是 C++11 引入的固定大小数组容器,替代传统 C 风格数组,兼具静态数组的性能和容器的便捷性(如迭代器、边界检查、成员函数)。它的大小在编译期确定,存储在栈上(相比 std::vector 更高效),且支持所有容器通用操作。

std::array 是 C++ 静态数组的最佳替代方案,核心优势:

1. 固定大小(编译期确定),栈存储,效率与原生数组一致;

2. 提供容器化接口(迭代器、成员函数),兼容 STL 算法;

3. 支持安全的边界检查(at())和编译期检查(std::get<I>);

4. 无额外内存开销(相比 vector 无动态分配)。

一、基础初始化与构造

std::array 支持多种初始化方式,核心特点是**大小必须是编译期常量**。

功能1:默认构造(空/零初始化)

- 语法:std::array<T, N> arr;

- 说明:

  - 若 T 是内置类型(int/float 等),默认值为零初始化(C++11 起);

  - 若 T 是自定义类型,调用默认构造函数。

示例:

#include <iostream>
#include <array>
int main() {
    // 默认构造:int 类型零初始化,所有元素为 0
    std::array<int, 5> arr1;
    std::cout << "默认构造的数组:";
    for (int num : arr1) {
        std::cout << num << " "; // 输出:0 0 0 0 0
    }
    std::cout << "\n";
    // 自定义类型默认构造
    struct Person {
        std::string name;
        int age = 18; // 类内初始值
    };
    std::array<Person, 2> arr2;
    std::cout << "自定义类型默认构造:" 
              << arr2[0].name << "(" << arr2[0].age << "), "
              << arr2[1].name << "(" << arr2[1].age << ")\n";
    // 输出:(18), (18)
    return 0;
}

功能2:聚合初始化(列表初始化)

- 语法:std::array<T, N> arr = {v1, v2, ..., vn};

- 说明:

  - 初始化列表元素个数可少于 N,剩余元素零初始化;

  - 个数不能超过 N(编译错误)。

示例:

#include <iostream>
#include <array>
int main() {
    // 完整初始化
    std::array<int, 3> arr1 = {10, 20, 30};
    std::cout << "完整初始化:";
    for (int num : arr1) std::cout << num << " "; // 10 20 30
    std::cout << "\n";
    // 部分初始化(剩余元素零初始化)
    std::array<double, 4> arr2 = {3.14, 2.718};
    std::cout << "部分初始化:";
    for (double num : arr2) std::cout << num << " "; // 3.14 2.718 0 0
    std::cout << "\n";
    // 直接列表初始化(省略 =)
    std::array<std::string, 2> arr3{"hello", "world"};
    std::cout << "字符串数组:" << arr3[0] << " " << arr3[1] << "\n"; // hello world
    return 0;
}

功能3:拷贝构造/赋值

- 语法:

  - 拷贝构造:std::array<T, N> arr2(arr1); 或 std::array<T, N> arr2 = arr1;

  - 拷贝赋值:arr2 = arr1;

- 说明:要求两个 array 的类型(T)和大小(N)完全一致。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 3> arr1 = {1, 2, 3};
    // 拷贝构造
    std::array<int, 3> arr2(arr1);
    std::cout << "拷贝构造:";
    for (int num : arr2) std::cout << num << " "; // 1 2 3
    std::cout << "\n";
    // 拷贝赋值
    std::array<int, 3> arr3;
    arr3 = arr1;
    std::cout << "拷贝赋值:";
    for (int num : arr3) std::cout << num << " "; // 1 2 3
    std::cout << "\n";
    return 0;
}

二、元素访问

std::array 提供多种安全/非安全的元素访问方式。

功能1:operator[](非安全访问)

- 语法:arr[index]

- 说明:

  - 无边界检查,越界行为未定义(可能崩溃);

  - 返回元素的引用,可读写。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 4> arr = {10, 20, 30, 40};
    // 读元素
    std::cout << "arr[2] = " << arr[2] << "\n"; // 30
    // 写元素
    arr[1] = 200;
    std::cout << "修改后 arr[1] = " << arr[1] << "\n"; // 200
    // 越界(未定义行为,可能崩溃)
    // std::cout << arr[10] << "\n"; 
    return 0;
}

功能2:at()(安全访问)

- 语法:arr.at(index)

- 说明:

  - 有边界检查,越界抛出 std::out_of_range 异常;

  - 返回元素的引用,可读写。

示例:

#include <iostream>
#include <array>
#include <stdexcept> // 异常头文件
int main() {
    std::array<int, 4> arr = {10, 20, 30, 40};
    try {
        // 安全读
        std::cout << "arr.at(3) = " << arr.at(3) << "\n"; // 40
        // 安全写
        arr.at(0) = 100;
        std::cout << "修改后 arr.at(0) = " << arr.at(0) << "\n"; // 100
        // 越界,抛出异常
        std::cout << arr.at(10) << "\n";
    } catch (const std::out_of_range& e) {
        std::cerr << "异常:" << e.what() << "\n"; // 输出:array::at: __n (which is 10) >= _Nm (which is 4)
    }
    return 0;
}

功能3:front()(访问第一个元素)

- 语法:arr.front()

- 说明:返回第一个元素的引用,无边界检查(空数组未定义)。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<std::string, 3> arr = {"apple", "banana", "cherry"};
    // 读第一个元素
    std::cout << "第一个元素:" << arr.front() << "\n"; // apple
    // 写第一个元素
    arr.front() = "orange";
    std::cout << "修改后第一个元素:" << arr.front() << "\n"; // orange
    return 0;
}

功能4:back()(访问最后一个元素)

- 语法:arr.back()

- 说明:返回最后一个元素的引用,无边界检查(空数组未定义)。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<double, 3> arr = {1.1, 2.2, 3.3};
    // 读最后一个元素
    std::cout << "最后一个元素:" << arr.back() << "\n"; // 3.3
    // 写最后一个元素
    arr.back() = 9.9;
    std::cout << "修改后最后一个元素:" << arr.back() << "\n"; // 9.9
    return 0;
}

功能5:data()(获取底层数组指针)

- 语法:arr.data()

- 说明:返回指向第一个元素的原生指针,可用于兼容 C 风格接口。

示例:

#include <iostream>
#include <array>
#include <cstring> // memcpy 头文件
int main() {
    std::array<int, 4> arr = {1, 2, 3, 4};
    // 获取原生指针
    int* ptr = arr.data();
    std::cout << "通过指针访问:";
    for (int i = 0; i < 4; ++i) {
        std::cout << ptr[i] << " "; // 1 2 3 4
    }
    std::cout << "\n";
    // 兼容 C 函数(如 memcpy)
    int buf[4];
    memcpy(buf, arr.data(), sizeof(arr));
    std::cout << "memcpy 后:";
    for (int num : buf) std::cout << num << " "; // 1 2 3 4
    std::cout << "\n";
    return 0;
}

三、容量与状态查询

功能1:size()(获取元素个数)

- 语法:arr.size()

- 说明:返回编译期常量(constexpr),等于数组的固定大小 N。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr1;
    std::array<std::string, 0> arr2; // 空数组
    std::cout << "arr1 大小:" << arr1.size() << "\n"; // 5
    std::cout << "arr2 大小:" << arr2.size() << "\n"; // 0
    // 编译期验证(constexpr 特性)
    static_assert(arr1.size() == 5, "arr1 大小必须为5");
    return 0;
}

功能2:max_size()(获取最大容量)

- 语法:arr.max_size()

- 说明:

  - 对于 std::array,max_size() 等于 size()(固定大小);

  - 与 vector 的 max_size() 区分(vector 是理论最大容量)。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 7> arr;
    std::cout << "size = " << arr.size() << "\n";       // 7
    std::cout << "max_size = " << arr.max_size() << "\n"; // 7
    return 0;
}

功能3:empty()(判断是否为空)

- 语法:arr.empty()

- 说明:

  - 返回 bool,仅当 size() == 0 时为 true;

  - 编译期常量(constexpr)。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 0> empty_arr;
    std::array<int, 3> non_empty_arr;
    std::cout << "空数组 empty():" << std::boolalpha << empty_arr.empty() << "\n"; // true
    std::cout << "非空数组 empty():" << non_empty_arr.empty() << "\n"; // false
    // 编译期判断
    static_assert(empty_arr.empty(), "空数组必须返回 true");
    return 0;
}

四、修改操作

功能1:fill()(填充所有元素)

- 语法:arr.fill(value)

- 说明:将数组所有元素赋值为 value,覆盖原有值。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 4> arr;
    // 填充所有元素为 9
    arr.fill(9);
    std::cout << "填充后:";
    for (int num : arr) std::cout << num << " "; // 9 9 9 9
    std::cout << "\n";
    // 填充自定义类型
    std::array<std::string, 2> str_arr;
    str_arr.fill("hello");
    std::cout << "字符串填充:" << str_arr[0] << " " << str_arr[1] << "\n"; // hello hello
    return 0;
}

功能2:swap()(交换两个数组)

- 语法:arr1.swap(arr2) 或 std::swap(arr1, arr2)

- 说明:

  - 两个数组的类型(T)和大小(N)必须完全一致;

  - 交换是 O(1) 操作(仅交换底层指针,无元素拷贝)。

示例:

#include <iostream>
#include <array>
#include <algorithm> // std::swap 头文件
int main() {
    std::array<int, 3> arr1 = {1, 2, 3};
    std::array<int, 3> arr2 = {10, 20, 30};
    // 方法1:成员函数 swap
    arr1.swap(arr2);
    std::cout << "arr1 交换后:";
    for (int num : arr1) std::cout << num << " "; // 10 20 30
    std::cout << "\n";
    std::cout << "arr2 交换后:";
    for (int num : arr2) std::cout << num << " "; // 1 2 3
    std::cout << "\n";
    // 方法2:std::swap
    std::swap(arr1, arr2);
    std::cout << "再次交换后 arr1:";
    for (int num : arr1) std::cout << num << " "; // 1 2 3
    std::cout << "\n";
    return 0;
}

五、迭代器支持

std::array 提供完整的迭代器接口,兼容 STL 算法。

功能1:begin()/end()(普通迭代器)

- 语法:

  - arr.begin():返回指向第一个元素的迭代器;

  - arr.end():返回指向最后一个元素**下一个位置**的迭代器(尾后迭代器)。

- 说明:迭代器可读写,支持遍历、算法操作。

示例:

#include <iostream>
#include <array>
#include <algorithm> // std::sort
int main() {
    std::array<int, 5> arr = {5, 2, 8, 1, 9};
    // 迭代器遍历
    std::cout << "迭代器遍历:";
    for (auto it = arr.begin(); it != arr.end(); ++it) {
        std::cout << *it << " "; // 5 2 8 1 9
    }
    std::cout << "\n";
    // 配合 STL 算法排序
    std::sort(arr.begin(), arr.end());
    std::cout << "排序后:";
    for (auto num : arr) std::cout << num << " "; // 1 2 5 8 9
    std::cout << "\n";
    return 0;
}

功能2:cbegin()/cend()(常量迭代器)

- 语法:

  - arr.cbegin():返回指向第一个元素的常量迭代器;

  - arr.cend():返回尾后常量迭代器。

- 说明:迭代器只读,不可修改元素,适合 const 场景。

示例:

#include <iostream>
#include <array>
// 常量数组参数,只能用 const 迭代器
void print_const_array(const std::array<int, 4>& arr) {
    std::cout << "常量迭代器遍历:";
    for (auto it = arr.cbegin(); it != arr.cend(); ++it) {
        // *it = 100; // 编译错误:常量迭代器不可写
        std::cout << *it << " ";
    }
    std::cout << "\n";
}
int main() {
    std::array<int, 4> arr = {10, 20, 30, 40};
    print_const_array(arr); // 10 20 30 40
    return 0;
}

功能3:rbegin()/rend()(反向迭代器)

- 语法:

  - arr.rbegin():返回指向最后一个元素的反向迭代器;

  - arr.rend():返回指向第一个元素**前一个位置**的反向尾后迭代器。

- 说明:反向遍历数组(从后往前)。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<std::string, 3> arr = {"a", "b", "c"};
    // 反向迭代器遍历
    std::cout << "反向遍历:";
    for (auto it = arr.rbegin(); it != arr.rend(); ++it) {
        std::cout << *it << " "; // c b a
    }
    std::cout << "\n";
    return 0;
}

功能4:crbegin()/crend()(常量反向迭代器)

- 语法:

  - arr.crbegin():返回指向最后一个元素的常量反向迭代器;

  - arr.crend():返回反向尾后常量迭代器。

- 说明:只读的反向遍历。

示例:

#include <iostream>
#include <array>
int main() {
    const std::array<int, 4> arr = {1, 2, 3, 4}; // 常量数组
    // 常量反向迭代器遍历
    std::cout << "常量反向遍历:";
    for (auto it = arr.crbegin(); it != arr.crend(); ++it) {
        std::cout << *it << " "; // 4 3 2 1
    }
    std::cout << "\n";
    return 0;
}

六、非成员函数

功能1:std::get<I>()(编译期索引访问)

- 语法:std::get<I>(arr)

- 说明:

  - I 是编译期常量(模板参数),越界会编译错误;

  - 返回第 I 个元素的引用,可读写。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 3> arr = {10, 20, 30};
    // 读元素(I=1)
    std::cout << "std::get<1>(arr) = " << std::get<1>(arr) << "\n"; // 20
    // 写元素
    std::get<0>(arr) = 100;
    std::cout << "修改后 get<0> = " << std::get<0>(arr) << "\n"; // 100
    // 越界(编译错误)
    // std::get<5>(arr); 
    return 0;
}

功能2:std::swap()(全局交换)

- 语法:std::swap(arr1, arr2)

- 说明:等价于成员函数 swap(),是对 std::array 的特化版本,效率更高。

示例:

#include <iostream>
#include <array>
#include <algorithm> // std::swap
int main() {
    std::array<double, 2> arr1 = {1.1, 2.2};
    std::array<double, 2> arr2 = {9.9, 8.8};
    std::swap(arr1, arr2);
    std::cout << "arr1: " << arr1[0] << " " << arr1[1] << "\n"; // 9.9 8.8
    std::cout << "arr2: " << arr2[0] << " " << arr2[1] << "\n"; // 1.1 2.2
    return 0;
}

功能3:比较运算符(==/!=/</<=/>/>=)

- 语法:arr1 == arr2、arr1 < arr2 等

- 说明:

  - 逐元素比较,要求两个数组大小和类型一致;

  - ==:所有元素相等则返回 true;

  - 关系运算符(</>)按字典序比较。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 3> arr1 = {1, 2, 3};
    std::array<int, 3> arr2 = {1, 2, 3};
    std::array<int, 3> arr3 = {1, 2, 4};
    std::array<int, 3> arr4 = {0, 9, 9};
    std::cout << "arr1 == arr2: " << std::boolalpha << (arr1 == arr2) << "\n"; // true
    std::cout << "arr1 == arr3: " << (arr1 == arr3) << "\n"; // false
    std::cout << "arr1 < arr3: " << (arr1 < arr3) << "\n";   // true(前两个元素相等,第三个 3<4)
    std::cout << "arr1 > arr4: " << (arr1 > arr4) << "\n";   // true(第一个元素 1>0)
    return 0;
}

七、扩展特性(C++17 及以上)

功能:std::array 的结构化绑定

- 语法:auto [a, b, c] = arr;

- 说明:C++17 引入,可直接解构数组元素,需元素个数匹配。

示例:

#include <iostream>
#include <array>
int main() {
    std::array<int, 3> arr = {10, 20, 30};
    // 结构化绑定
    auto [x, y, z] = arr;
    std::cout << "x = " << x << ", y = " << y << ", z = " << z << "\n"; // 10 20 30
    // 绑定引用(可修改)
    auto& [rx, ry, rz] = arr;
    rx = 100;
    std::cout << "修改后 arr[0] = " << arr[0] << "\n"; // 100
    return 0;
}

C++编程语言基础