c++oding="utf-8" ?>
c++11起std::list支持list l{1,2,3}统一列表初始化;增删操作:push_front()/push_back()常数时间插入,erase()或pop_front()/pop_back()删除,不支持下标访问。

list 初始化和基本增删操作怎么写
std::list 是双向链表,不支持随机访问,但插入删除是常数时间。初始化时别用 list<int> l = {1,2,3}</int> 这种初始化列表语法(C++11 起支持,但某些老编译器或 STL 实现可能报错),稳妥写法是直接构造加 push_back 或用迭代器范围构造。
-
list<int> l{1, 2, 3}</int>—— 推荐,C++11 及以上标准明确支持 -
l.push_front(0)和l.push_back(4)插入头尾,比vector快,无内存搬移 - 删元素别用下标:list 没有
operator[],想删第 n 个得先advance(it, n)移动迭代器,再erase(it) -
l.erase(l.begin())删首、l.pop_front()也删首,但后者不返回值,前者返回下一位置迭代器
遍历 list 为什么不能用 for(int i=0; il.size() 在某些 STL 实现里是 O(n) 的(比如早期 GCC libstdc++),因为要遍历计数;即使现在多数是 O(1),但下标访问本身就不合法——list 迭代器是 BidirectionalIterator,不支持 it + i 运算。硬写 l[i] 编译直接失败。
- 必须用迭代器遍历:
for (auto it = l.begin(); it != l.end(); ++it)
- 或范围 for:
for (int x : l) —— 安全、简洁,底层仍是迭代器
- 想反向遍历?用
rbegin()/rend(),不是 end()--,后者对空 list 会 UB
list::splice 怎么高效移动节点而不拷贝
splice 是 list 独有的优势操作:把另一个 list 的一段“剪切”过来,只改指针,零拷贝。常见误用是传错参数顺序或忽略源容器状态变化。
-
dst.splice(dst.end(), src, src.begin()) —— 把 src 首节点移到 dst 尾部
-
dst.splice(dst.begin(), src, it1, it2) —— 移动 [it1, it2) 区间,注意是左闭右开
- 移动后,被 splice 的节点从
src 中消失,src 大小减小,但 src 本身仍有效(哪怕变空)
- 不能跨容器 splice 同一个 list 的区间(如
l.splice(l.begin(), l, it)),行为未定义
什么时候该用 list 而不是 vector 或 deque
除非你明确需要频繁在任意位置插入/删除,且不关心随机访问和缓存局部性,否则大概率不该选 list。实测中,现代 CPU 上 vector 插入末尾 + erase 中间(配合 remove_if)往往比 list 快得多。
- 适合场景:实现 LRU cache(需快速把某节点提到头部)、事件队列(按优先级插入中间)
- 不适合场景:存大量小对象(指针开销翻倍)、需要二分查找(得先转成 vector 或用 set)、多线程频繁遍历(cache line 不友好)
-
list 迭代器仅在被 erase 的节点上失效,其余全部保持有效;而 vector 一插入就可能导致所有迭代器失效
真正用好 list 的关键,不是记住 API,而是理解它解决的是“高频局部修改 + 低频遍历”的特定问题。一旦需求偏移,性能反而更差。
l.size() 在某些 STL 实现里是 O(n) 的(比如早期 GCC libstdc++),因为要遍历计数;即使现在多数是 O(1),但下标访问本身就不合法——list 迭代器是 BidirectionalIterator,不支持 it + i 运算。硬写 l[i] 编译直接失败。
- 必须用迭代器遍历:
for (auto it = l.begin(); it != l.end(); ++it) - 或范围 for:
for (int x : l)—— 安全、简洁,底层仍是迭代器 - 想反向遍历?用
rbegin()/rend(),不是end()--,后者对空 list 会 UB
list::splice 怎么高效移动节点而不拷贝
splice 是 list 独有的优势操作:把另一个 list 的一段“剪切”过来,只改指针,零拷贝。常见误用是传错参数顺序或忽略源容器状态变化。
-
dst.splice(dst.end(), src, src.begin())—— 把src首节点移到dst尾部 -
dst.splice(dst.begin(), src, it1, it2)—— 移动 [it1, it2) 区间,注意是左闭右开 - 移动后,被 splice 的节点从
src中消失,src大小减小,但src本身仍有效(哪怕变空) - 不能跨容器 splice 同一个 list 的区间(如
l.splice(l.begin(), l, it)),行为未定义
什么时候该用 list 而不是 vector 或 deque
除非你明确需要频繁在任意位置插入/删除,且不关心随机访问和缓存局部性,否则大概率不该选 list。实测中,现代 CPU 上 vector 插入末尾 + erase 中间(配合 remove_if)往往比 list 快得多。
- 适合场景:实现 LRU cache(需快速把某节点提到头部)、事件队列(按优先级插入中间)
- 不适合场景:存大量小对象(指针开销翻倍)、需要二分查找(得先转成 vector 或用 set)、多线程频繁遍历(cache line 不友好)
-
list迭代器仅在被 erase 的节点上失效,其余全部保持有效;而vector一插入就可能导致所有迭代器失效
真正用好 list 的关键,不是记住 API,而是理解它解决的是“高频局部修改 + 低频遍历”的特定问题。一旦需求偏移,性能反而更差。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











