vector 容器的扩容机制是怎样的?
·
一、vector 扩容的本质
vector 是连续内存的动态数组。因为内存必须连续,所以不能在原有内存后面 “追加”,只能:
- 申请一块更大的新连续内存
- 把旧内存里的所有元素拷贝 / 移动到新内存
- 释放旧内存
- 插入新元素
- 更新内部指针指向新内存
这就是扩容。
二、size 和 capacity 的区别(必须懂)
- size():当前容器实际拥有的元素个数
- capacity():当前已经分配的总容量(能装多少个才需要扩容)
只有当 size() == capacity() 时,再插入元素才会触发扩容。
三、扩容倍数(不同编译器不同)
扩容不是 + 1,而是按固定倍数扩展,以减少频繁扩容。
-
GCC / Clang(Linux、Mac、Android)扩容倍数:2 倍序列:0 → 1 → 2 → 4 → 8 → 16 → 32 → 64…
-
MSVC(VS 编译器)扩容倍数:1.5 倍序列:0 → 1 → 2 → 3 → 4 → 6 → 9 → 13…
为什么是 1.5 或 2 倍?因为空间分配效率和内存碎片之间的平衡。
四、完整扩容流程(详细步骤)
假设 vector 当前:size = 4,capacity = 4再 push_back 一个元素,触发扩容:
- 计算新容量:
new_cap = old_cap * 2→ 8 - 申请新内存 8 个元素大小
- 将旧内存 4 个元素移动 / 拷贝到新内存
- 简单类型(int):拷贝
- 复杂对象:移动构造(C++11 后),效率更高
- 释放旧内存
- 在新内存第 5 个位置插入新元素
- size 变为 5,capacity 变为 8
五、扩容带来的重要后果
1. 迭代器、指针、引用全部失效
扩容后内存地址变了,原来的迭代器 / 指针都变成野指针。
cpp
运行
auto it = v.begin();
v.push_back(x); // 可能扩容
// it 已经无效!
2. 扩容是昂贵操作
数据量大时,拷贝 / 移动所有元素非常耗时。
3. vector 不会自动缩容
erase、clear 只改变 size,不释放 capacity。想缩容必须手动:
cpp
运行
v.shrink_to_fit();
4. 多次扩容会产生内存碎片
尤其 2 倍扩容,旧内存永远无法被重复利用。所以 1.5 倍更利于内存复用。
六、如何避免频繁扩容?
提前预留空间,一次性分配足够容量:
cpp
运行
vector<int> v;
v.reserve(1000); // 直接分配 capacity=1000
这样插入 1000 个元素都不会扩容。
七、一句话总结(面试背诵版)
vector 是连续内存动态数组,当 size == capacity 时触发扩容。扩容会申请原容量 1.5 或 2 倍的新内存,将元素拷贝 / 移动过去,释放旧内存。扩容代价高,会导致迭代器失效,可通过 reserve 预先分配容量避免频繁扩容。
更多推荐




所有评论(0)