C++ 标准特性:array & forward_list
一、array(STL array 容器)------ C++11
1.1 概述
std::array 是 C++11 标准中新增的序列容器,它封装了固定大小的 C 风格数组。
| 特性 |
说明 |
| 头文件 |
<array> |
| 大小 |
编译期确定,不可动态改变 |
| 底层 |
封装 C 风格数组 |
| 优势 |
比原生数组更安全,支持迭代器和 STL 算法 |
与 vector 的区别 |
vector 大小可变,array 大小固定,array 性能更接近原生数组 |
1.2 示例代码
#include <iostream>
#include <array> // array容器
using namespace std;
int main()
{
std::array<int, 5> arr{ };
// 初始化arr容器
for (int i = 1; i < arr.size(); i++) {
arr.at(i) = i;
}
// 通过get()重载函数输出指定位置元素值
cout << "输出结果为" << get<4>(arr) << endl;
return 0;
}
1.3 代码解析
array<int, 5> arr{}; // 创建 int 类型、大小为 5 的 array,初始值为 0
arr.at(i) = i; // 带越界检查的访问(越界时抛 std::out_of_range)
arr[i] = i; // 另一种访问方式(不检查越界,性能更高)
get<4>(arr); // 编译期索引访问,索引越界会在编译时报错
| 访问方式 |
检查时机 |
安全性 |
arr[i] |
无检查 |
⚠️ 越界未定义行为 |
arr.at(i) |
运行时检查 |
✅ 越界抛异常 |
get<N>(arr) |
编译期检查 |
✅✅ 索引越界编译失败 |
1.4 常用成员函数速查
| 函数 |
功能 |
size() |
返回元素个数 |
at(i) |
带越界检查的元素访问 |
operator[i] |
不带越界检查的访问 |
front() |
返回第一个元素 |
back() |
返回最后一个元素 |
data() |
返回指向底层数组的指针 |
fill(x) |
将所有元素填充为 x |
swap(other) |
交换两个 array 的内容 |
二、forward_list(前向链表)------ C++11
2.1 概述
std::forward_list 是 C++11 新增的容器,底层实现采用单向链表。
| 对比 |
forward_list |
list |
| 链表类型 |
单向链表 |
双向链表 |
| 方向 |
只能向前遍历 |
可向前/向后遍历 |
| 内存开销 |
每个节点只存一个指针 |
每个节点存两个指针(next + prev) |
| 插入/删除位置 |
只能在指定位置之后插入 |
可在指定位置之前或之后插入 |
| 适用场景 |
节省内存、只需单向遍历 |
需要双向遍历和灵活插入 |
forward_list: 节点 → 节点 → 节点 → end
(只有 next 指针)
list: 节点 ⇄ 节点 ⇄ 节点 ⇄ end
(有 next 和 prev 指针)
2.2 示例代码
#include <iostream>
#include <forward_list>
using namespace std;
int main()
{
forward_list<int> values{ 11,22,33 };
values.emplace_front(40); // 在头部插入 40
cout << "第一次输出结果为:" << endl;
for (auto i = values.begin(); i != values.end(); i++) {
cout << *i << " ";
}
values.emplace_after(values.before_begin(), 50); // 在头部之前插入 50
cout << "\n\n第二次输出结果为:" << endl;
for (auto i = values.begin(); i != values.end(); i++) {
cout << *i << " ";
}
values.reverse(); // 反转链表
cout << "\n\nreverse后输出结果为:" << endl;
for (auto i = values.begin(); i != values.end(); i++) {
cout << *i << " ";
}
return 0;
}
2.3 执行过程分析
| 步骤 |
操作 |
链表状态 |
| 初始 |
{11, 22, 33} |
11 → 22 → 33 |
emplace_front(40) |
头部插入 40 |
40 → 11 → 22 → 33 |
emplace_after(before_begin(), 50) |
在"头部之前"插入 50 |
50 → 40 → 11 → 22 → 33 |
reverse() |
反转链表 |
33 → 22 → 11 → 40 → 50 |
before_begin() 返回一个指向第一个元素之前的迭代器。因为单向链表只能向后看,要操作头部位置,需要这个"头前"迭代器。
2.4 常用成员函数速查
| 函数 |
功能 |
emplace_front(args...) |
在头部原地构造元素 |
push_front(x) |
在头部插入元素 |
pop_front() |
移除头部元素 |
emplace_after(it, args...) |
在指定位置之后原地构造 |
insert_after(it, x) |
在指定位置之后插入 |
erase_after(it) |
删除指定位置之后的元素 |
before_begin() |
返回头前迭代器(用于操作第一个元素之前的位置) |
reverse() |
反转链表 |
empty() / clear() |
判空 / 清空 |
sort() / merge() |
排序 / 合并有序链表 |
三、array vs forward_list 对比
| 特性 |
array |
forward_list |
| 头文件 |
<array> |
<forward_list> |
| 底层结构 |
静态数组 |
单向链表 |
| 大小 |
编译期固定 |
动态增减 |
| 随机访问 |
✅ O(1) |
❌ |
| 遍历方向 |
双向(通过索引) |
单向(向前) |
| 插入/删除复杂度 |
❌ 不支持 |
O(1)(指定位置之后) |
| 内存连续性 |
✅ 连续 |
❌ 非连续 |
| 适用场景 |
固定大小、需要随机访问 |
频繁插入删除、内存敏感 |