forward_list是C++11引入的单向链表,仅存后继指针,不支持反向遍历、无O(1) size()(C++17前)、不可随机访问;与list根本区别在于单向性、更小内存开销及仅提供_insert_after/erase_after等后置操作接口。

forward_list 是什么,和 list 有什么根本区别
forward_list 是 C++11 引入的单向链表容器,底层只保存指向下一个节点的指针,不存前驱。它比 list 更轻量:内存开销更小(每个节点少一个指针)、插入删除略快(无需维护双向链接),但**不支持反向遍历、不提供 size() 成员函数(C++11/14 中是 O(n))、不能随机访问、没有 begin() - 1 这类操作**。
如果你只需要从前到后遍历、频繁在任意位置插入/删除、且极度在意内存或缓存局部性,forward_list 才值得考虑;否则直接用 vector 或 list 更稳妥。
如何正确声明、初始化和遍历 forward_list
声明时必须指定元素类型,不支持默认构造出“空容器但有 size()”这种错觉——forward_list 的 size() 在 C++17 才变成 O(1),之前标准里它压根没这个成员函数(部分编译器扩展了,但不可靠)。
- 初始化推荐用花括号列表:
forward_list
fl = {1, 2, 3, 4}; - 遍历只能用正向迭代器:
for (auto it = fl.begin(); it != fl.end(); ++it) { /* ... */ },不能用--it或it + 2 - 想获取长度?别调
fl.size()(C++14 及以前可能编译失败或返回 0),老实用std::distance(fl.begin(), fl.end()),但它是 O(n)
insert_after 和 emplace_after 怎么用才不踩坑
forward_list 所有修改操作都以 *_after 命名,因为必须指定「在哪个节点之后」操作——它没有「在 pos 位置插入」这种接口,insert_after(pos, val) 的 pos 是迭代器,代表「插在 pos 指向节点的后面」,不是插在 pos 位置。
立即学习“C++免费学习笔记(深入)”;
-
fl.insert_after(fl.before_begin(), 42)等价于push_front(42),这是唯一能头插的方式 -
fl.emplace_after(it, args...)直接在it后构造对象,避免临时对象拷贝,比insert_after更高效 - 注意:
before_begin()返回的是特殊迭代器,不能解引用;fl.begin()才指向第一个有效元素 - 如果
it是fl.end(),insert_after(it, x)行为未定义(不是尾插!尾插只能靠循环找到倒数第二个节点再插)
erase_after 删除逻辑和常见误用
erase_after(pos) 删除的是 pos 后面那个节点,不是 pos 本身。所以头删要写成 fl.erase_after(fl.before_begin());删第二个元素是 fl.erase_after(fl.begin())。
- 批量删除区间:
fl.erase_after(first, last),删的是first后面直到(不含)last的所有节点,即[next(first), last) - 想删掉所有值为
x的节点?不能边遍历边 erase_after(会失效迭代器),得用remove_if配合erase_after,或者手动维护前驱:auto prev = fl.before_begin(); while (next(prev) != fl.end()) { if (*next(prev) == x) fl.erase_after(prev); else ++prev; } - 没有
clear()的快捷方式?有,但它是 O(n):直接赋值fl = {}或调用fl.erase_after(fl.before_begin(), fl.end())
真正用 forward_list 的时候,多数人卡在「找不到头插/尾插直观写法」和「误以为 size() 是常数时间」这两点。它不是一个通用替代品,而是一个特定场景下的窄接口工具——接口少,意味着责任明确,也意味着你得自己多想一步。










