c++oding="utf-8" ?>
fl.empty()是唯一安全的空判断方式,因size()在gcc旧版等环境中可能未实现、崩溃或返回错误值,而empty()是标准强制o(1)且保证定义的接口。

别用 size() 判空,也别传 fl.begin() 给 erase_after() —— 这两类写法在 GCC 旧版、嵌入式裁剪 STL 或裸机环境里,大概率直接崩溃或删错节点。
为什么 fl.empty() 是唯一安全的空判断方式
std::forward_list::size() 在 libstdc++(GCC 默认)中至今未实现计数器,每次调用都是 std::distance(fl.begin(), fl.end()) 全链表遍历;某些旧版本甚至不定义该函数,fl.size() == 0 可能编译失败、返回垃圾值,或触发断言。而 empty() 是标准强制要求 O(1) 且 guaranteed defined 的接口。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 永远写
if (fl.empty()),而不是if (fl.size() == 0)或if (!fl.size()) - 若真需要长度且只查一次:用
auto len = std::distance(fl.begin(), fl.end()),结果存局部变量复用 - 若高频访问长度(如 LRU 缓存计数器):手动维护一个
size_t m_size,并在每次push_front()、insert_after()、erase_after()后同步增减 - 绝对禁止在循环条件里写
for (size_t i = 0; i —— 这会让本应 O(n) 的遍历退化成 O(n²)
insert_after() 和 erase_after() 的参数到底指谁
这两个函数的操作对象永远是「参数迭代器所指节点的下一个节点」,不是参数本身。这是单向链表无法回溯的硬约束,不是 API 设计疏漏。传错迭代器会删错位置、跳过节点,甚至触发未定义行为。
- 头插唯一安全写法:
fl.insert_after(fl.before_begin(), val)或更优的fl.emplace_front(val) - 删首节点必须用:
fl.erase_after(fl.before_begin())(等价于fl.pop_front());传fl.begin()给erase_after()实际删的是第二个元素 - 删第 n 个元素(n ≥ 1):
auto prev = std::next(fl.before_begin(), n - 1)获取前驱,再fl.erase_after(prev) - 边遍历边删当前匹配节点:初始化
auto prev = fl.before_begin(),循环内用auto curr = std::next(prev)定位,匹配后执行prev = fl.erase_after(prev)(它返回被删节点之后的有效迭代器) - 绝不可传
fl.end()给任一函数 —— 未定义行为,GCC/Clang 可能静默崩溃,MSVC 可能触发断言
为什么 splice_after() 是唯一值得手写的高性能操作
splice_after() 是 std::forward_list 唯一真正 O(1) 的物理拼接操作:不调用构造/析构、不分配内存、不拷贝数据,只改 next 指针。任何用 insert_after() 循环插入或 push_front() 模拟拼接的方式,都会触发 n 次内存分配和构造,彻底毁掉它的内存与性能优势。
- 整链迁移:
dst.splice_after(pos, src),执行后src变为空容器 - 单节点迁移:
dst.splice_after(pos, src, it),仅将src中it所指节点移至dst的pos后,it在src中立即失效 - 范围迁移:
dst.splice_after(pos, src, first, last),拼接[first, last)左闭右开区间 - 典型场景:LRU 缓存中把命中节点提到头部 →
fl.splice_after(fl.before_begin(), fl, it);任务队列分片迁移时整段切走
最容易被忽略的点是:splice_after() 要求源与目标容器类型严格一致,且不能自拼接(fl.splice_after(pos, fl, ...) 是未定义行为);另外,所有基于 std::next() 的索引定位都必须确保不越界——对空链表调用 std::next(fl.before_begin(), 0) 是合法的,但 std::next(fl.begin(), 0) 在空链表上会解引用 fl.end(),导致未定义行为。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










