vector 的扩容机制
vector 的扩容机制是指当现有容量不足以容纳新元素时,自动分配更大的内存空间、复制旧元素到新空间,并释放旧空间的过程。其核心逻辑是 **“以空间换时间”**,通过预留额外容量减少频繁扩容的开销。
一、关键概念
在理解扩容机制前,先明确 vector 的两个核心属性:
- size:当前已存储的元素数量。
- capacity:当前分配的内存可容纳的最大元素数量(capacity >= size)。
当 size == capacity 时,再插入元素就会触发扩容。
二、扩容的完整流程
- 判断是否需要扩容
当执行 push_back、insert 等插入操作时,若 size + 新增元素数 > capacity,则触发扩容。
- 计算新容量
不同编译器(如 GCC、MSVC)的扩容策略略有差异,通常是 “当前容量的 1.5 倍或 2 倍”:
- GCC:新容量 = 旧容量 × 1.5(整数除法,如旧容量 5 → 新容量 7)。
 
- MSVC:新容量 = 旧容量 × 2(如旧容量 5 → 新容量 10)。
 
- 若初始容量为 0(空 vector),首次扩容通常直接分配能容纳 1 个元素的空间,后续按倍数增长。
 
- 分配新内存
根据新容量在堆上分配一块更大的连续内存(类型为元素类型的数组)。
- 复制 / 移动旧元素
将旧内存中的元素逐个复制(或移动,C++11 后)到新内存中。
- 释放旧内存
销毁旧内存中的元素,释放旧内存空间。
- 更新内部指针
将 vector 内部指向数据的指针(如 _M_start、_M_end、_M_capacity)指向新内存,并更新 size 和 capacity。
三、代码示例与验证
通过示例观察 vector 的 size、capacity 变化,验证扩容机制:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
// 初始状态:size=0,capacity=0
std::cout << "初始: size=" << v.size() << ", capacity=" << v.capacity() << std::endl;
// 插入元素,观察扩容
for (int i = 0; i < 10; ++i) {
v.push_back(i);
std::cout << "插入" << i << ": size=" << v.size() 
<< ", capacity=" << v.capacity() << std::endl;
}
return 0;
}
GCC 环境下的输出(1.5 倍扩容):
初始: size=0, capacity=0
插入0: size=1, capacity=1 // 首次扩容到1
插入1: size=2, capacity=2 // 1×2=2(因1.5取整后仍为1,故直接扩到2)
插入2: size=3, capacity=3 // 2×1.5=3
插入3: size=4, capacity=4 // 3×1.5=4.5→取整4
插入4: size=5, capacity=6 // 4×1.5=6
插入5: size=6, capacity=6
插入6: size=7, capacity=9 // 6×1.5=9
插入7: size=8, capacity=9
插入8: size=9, capacity=9
插入9: size=10, capacity=13 // 9×1.5=13.5→取整13
MSVC 环境下的输出(2 倍扩容):
初始: size=0, capacity=0
插入0: size=1, capacity=1 // 首次扩容到1
插入1: size=2, capacity=2 // 1×2=2
插入2: size=3, capacity=4 // 2×2=4
插入3: size=4, capacity=4
插入4: size=5, capacity=8 // 4×2=8
插入5: size=6, capacity=8
插入6: size=7, capacity=8
插入7: size=8, capacity=8
插入8: size=9, capacity=16 // 8×2=16
插入9: size=10, capacity=16
四、扩容的影响与优化
- 性能开销
扩容涉及内存分配、元素复制和旧内存释放,频繁扩容会导致性能下降(尤其是元素为大型对象时,复制成本高)。
- 迭代器失效
扩容后,旧内存被释放,指向旧内存的迭代器、指针、引用都会失效(需重新获取)。
- 优化策略
- 提前调用 reserve(n):手动预留足够容量(capacity 直接扩到 n),避免多次自动扩容。
 
例:v.reserve(10); 可让上述示例中 capacity 直接从 0 变为 10,插入 10 个元素时不再扩容。
- 避免存储大量大型对象:可存储指针(或智能指针),减少复制成本。
 
总结
vector 的扩容机制是 **“当容量不足时,按当前容量的 1.5 倍或 2 倍分配新内存,复制旧元素后释放旧内存”**,其设计平衡了内存利用率和操作效率。实际使用中,可通过 reserve 提前预留容量优化性能。
