std::list 是存储 int 的最直接方式,无需手写节点、管理指针或手动 new;需包含 头文件并正确声明类型,优先用 push_back/push_front 而非 insert,避免存指针以防内存泄漏,对 int 用 push_back 或 emplace_back 效果相同,遍历时禁用 size() 控制循环。

用 std::list<int></int> 存 int 最直接的方式
不用手写链表节点、不用管指针、不手动 new,C++ 标准库的 std::list 就是干这个的。它底层是双向链表,但你只管存取,内存管理全由容器负责。
常见错误现象:list.push_back(42) 编译失败?多半是没加 #include <list></list> 或忘了 using std::list(或写成 std::list<int></int>)。
- 声明:
std::list<int> nums;</int> - 添加单个值:
nums.push_back(10);或nums.push_front(-5); - 批量添加:
nums.assign({1, 2, 3});或循环调用push_back - 别用
list.insert(list.begin(), 42)去“头插”——除非真需要插入到特定位置;push_front更清晰、语义明确
为什么不用 std::list<int></int> 存 int 指针
新手容易想“链表不是存指针吗”,于是写 std::list<int> ptrs;</int> 再 ptrs.push_back(new int(42)); ——这会引入内存泄漏和所有权混乱。
使用场景:只有当你需要共享同一块 int 内存、或该 int 生命周期远超 list 本身时,才考虑指针。绝大多数情况,存值就够了。
立即学习“C++免费学习笔记(深入)”;
-
std::list<int></int>每次拷贝的是值,安全、独立、自动析构 -
std::list<int></int>存的是地址,你得自己delete,且无法判断谁该负责释放 - 性能影响:int 是 trivial 类型,拷贝开销极小(通常就一条 mov 指令),没必要绕路用指针
- 兼容性:存指针后,遍历必须解引用(
*it),代码更啰嗦,也更容易出现nullptr解引用崩溃
list::emplace_back 和 push_back 的实际区别
两者都能加 int,但行为不同:对 int 这种内置类型,效果完全一样;但理解差异能帮你避开后续坑。
常见错误现象:看到别人用 emplace_back 就跟风,结果在复杂类型里传错参数,编译报一堆模板错误。
-
push_back(42):先构造临时int(42),再移动/拷贝进节点 -
emplace_back(42):直接在 list 内部节点内存上“原地”构造int,省一次临时对象 - 对
int来说,编译器基本都优化掉了差别,不必纠结选哪个 - 真正有意义的场景是存自定义类(比如
std::list<:string></:string>),这时emplace_back("hello")可避免字符串临时对象构造 - 别对
int写emplace_back(std::move(x))——int没移动语义,std::move白加,还干扰阅读
迭代遍历时别误用 list::size() 做循环条件
虽然 nums.size() 能返回长度,但用它控制 for 循环,在 list 上是典型低效写法。
使用场景:当你需要按索引随机访问(比如“第 3 个元素”),std::list 本就不适合——它没有 O(1) 下标访问,nums[i] 是非法的,std::next(nums.begin(), i) 是 O(n)。
- 正确遍历方式:用范围 for 或迭代器 while 循环
for (int x : nums) { /* ... */ }或for (auto it = nums.begin(); it != nums.end(); ++it) - 错误写法:
for (size_t i = 0; i ——每次调用 <code>size()虽然 C++11 后是 O(1),但循环体里若再用std::advance找第 i 个,整体变成 O(n²) - 性能影响:list 的
size()在部分老标准库实现里甚至是 O(n),虽现代基本都是 O(1),但习惯上仍不该依赖它做高频判断 - 容易被忽略的地方:erase 某个迭代器后,别继续用那个迭代器,也别假设后续迭代器“自动偏移”——list 的迭代器在 erase 后仅当前失效,其他不受影响,这点和 vector 不同










