一、vector 扩容的本质

vector 是连续内存的动态数组。因为内存必须连续,所以不能在原有内存后面 “追加”,只能:

  1. 申请一块更大的新连续内存
  2. 把旧内存里的所有元素拷贝 / 移动到新内存
  3. 释放旧内存
  4. 插入新元素
  5. 更新内部指针指向新内存

这就是扩容


二、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 一个元素,触发扩容:

  1. 计算新容量:new_cap = old_cap * 2 → 8
  2. 申请新内存 8 个元素大小
  3. 将旧内存 4 个元素移动 / 拷贝到新内存
    • 简单类型(int):拷贝
    • 复杂对象:移动构造(C++11 后),效率更高
  4. 释放旧内存
  5. 在新内存第 5 个位置插入新元素
  6. 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 预先分配容量避免频繁扩容。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐