c++oding="utf-8" ?>
应使用 fl.empty() 判空而非 fl.size(),因 size() 在多数实现中为 O(n) 甚至未定义;需 O(1) 长度时须手动维护 m_size 成员并同步更新。

在嵌入式系统或高频内存敏感场景中,用 std::forward_list 替代 std::list 或 std::vector 时,若误调 size() 判空、传错 erase_after() 参数或用 insert_after() 循环拼接,轻则性能雪崩,重则静默崩溃或未定义行为——必须严格遵循其单向链表语义才能兑现极致内存节省承诺。
安全判空与长度管理
永远用 【fl.empty()】 替代 fl.size() == 0 或 !fl.size()。size() 在 GCC 默认 libstdc++(含 12/13/14)中仍是 std::distance(fl.begin(), fl.end()),即全链表遍历;部分裁剪 STL 根本不提供该函数,调用直接编译失败;更糟的是某些旧实现返回未初始化值,if (fl.size() == 0) 可能恒为 false 或触发 SIGSEGV。
若需一次长度值:执行 auto len = std::distance(fl.begin(), fl.end()),结果存为局部变量复用。
若长度需高频访问(如 LRU 缓存计数器):手动维护 size_t m_size 成员,在每次 push_front()、insert_after()、erase_after() 后同步增减——这是唯一可移植的 O(1) 长度方案。
绝对禁止在 for 循环条件中写 for (size_t i = 0; i
插入与删除操作的前驱依赖规则
方法一:头插安全写法
使用 fl.push_front(x) 或 fl.insert_after(fl.before_begin(), x)。绝不可用 fl.insert_after(fl.begin(), x),后者实际在首节点之后插入,等效于插到第二个位置。
方法二:删首节点
必须调用 fl.pop_front() 或 fl.erase_after(fl.before_begin())。传 fl.begin() 给 erase_after() 会删掉第二个元素,不是第一个——这是最常见误用,且无编译期提示。
方法三:删第 n 个元素(n ≥ 1)
① 先获取前驱:auto prev = std::next(fl.before_begin(), n - 1)
② 再执行删除:fl.erase_after(prev)
注意是 n - 1,不是 n;传 n 会越界或删错位置。
方法四:边遍历边删匹配节点
初始化 auto prev = fl.before_begin();循环内用 auto curr = std::next(prev) 定位当前节点;匹配后执行 prev = fl.erase_after(prev),它返回被删节点之后的有效迭代器,确保不跳过下一节点。
【绝对禁止传 fl.end() 给 insert_after()、erase_after() 或 std::next()】——未定义行为,GCC/Clang 常静默崩溃,MSVC 可能触发断言。
splice_after():唯一不可替代的 O(1) 物理拼接操作
splice_after() 是 forward_list 中唯一不调用构造/析构、不分配内存、不拷贝数据、只修改 next 指针的拼接方式。任何用 insert_after() 循环插入或 push_front() 模拟拼接的行为,都会触发 n 次内存分配和对象拷贝,彻底毁掉它的内存与性能优势。
整链迁移:dst.splice_after(pos, src),执行后 src 变为空容器,dst 在 pos 后接入全部原 src 节点。
单节点迁移:dst.splice_after(pos, src, it),仅将 src 中 it 所指节点移到 dst 的 pos 后;it 必须为 src 的有效非 end() 迭代器,且在迁移后立即失效。
范围迁移:dst.splice_after(pos, src, first, last),只拼接 [first, last) 区间(左闭右开);first 和 last 必须同属 src,且 first 可等于 last(此时不移动任何节点)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











