std::list是双向链表,不支持随机访问,operator[]和at()不存在,访问第n个元素需O(n)遍历;适用频繁插入/删除且需稳定迭代器的场景,如LRU缓存;迭代器仅erase的元素失效,其余保持有效。

std::list 是双向链表,不是数组或 vector
它不支持随机访问,operator[] 和 at() 都不存在。想取第 n 个元素,必须从头(或尾)开始走指针,时间复杂度 O(n)。如果代码里写了 my_list[5],编译直接报错:no match for operator[]。
适用场景很明确:频繁在任意位置插入/删除(尤其头部和中间),且不关心下标访问。比如实现 LRU 缓存、任务调度队列、需要稳定迭代器的场景。
- 插入用
push_front()、push_back()、insert();删除用pop_front()、pop_back()、erase() -
insert()接收迭代器位置 + 值(或范围),不能传整数下标 - 遍历时优先用范围 for 或
begin()/end(),别手写for (int i = 0; ...)
迭代器失效规则和 vector 完全不同
std::list 的迭代器在插入/删除时几乎不失效——这是它和 std::vector 最关键的区别。只有被 erase() 的那个迭代器本身失效;其余所有迭代器(包括指向其他元素的、end())全部保持有效。
这意味着你可以安全地边遍历边删满足条件的元素,不用像 vector 那样担心迭代器“跳过”或“越界”:
立即学习“C++免费学习笔记(深入)”;
for (auto it = lst.begin(); it != lst.end(); ) {
if (*it % 2 == 0) {
it = lst.erase(it); // erase 返回下一个有效迭代器
} else {
++it;
}
}
但注意:lst.clear() 会让所有现存迭代器失效;splice() 不影响迭代器有效性,是移动节点而非拷贝。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
不要忽略 size() 的性能差异(C++11 之后已修复)
C++11 起,std::list::size() 是 O(1),内部维护了计数器。但如果你在老标准(C++98/03)环境下编译,或者用了某些不合规的 STL 实现,size() 可能是 O(n) —— 它得遍历整个链表数节点。
所以实际项目中,如果不确定编译环境或第三方库行为,更稳妥的做法是自己维护一个 size_t count 变量,尤其在循环条件里避免反复调用 size():
- 别写
for (int i = 0; i (即使 C++11 合法,语义也不对) - 改用
while (!lst.empty())或基于迭代器的循环 - 若真需长度,且确定是 C++11+ 标准,
lst.size()可放心用
list 的 splice() 是唯一能“零拷贝移动”的操作
splice() 把另一个 list(或自身某段)的节点直接接到当前 list 中,不构造、不析构、不分配内存。它是 std::list 真正不可替代的价值点。
常见误用是试图用 assign() 或 insert() 搬数据,结果触发大量拷贝:
-
dst.splice(dst.end(), src):把 src 全部移到 dst 尾部,src 变空 -
dst.splice(it, src, src_it):把 src 中单个节点移到 dst 的 it 前 -
dst.splice(it, src, first, last):移动 [first, last) 区间(注意是左闭右开)
注意:被 splice 的节点必须来自另一个 list(或同一 list),且不能是目标位置的迭代器本身,否则行为未定义。

















