vector扩容在size()等于capacity()时触发,如push_back、insert或resize超容时;reserve仅预分配不构造;扩容导致迭代器失效且开销大;vector是特例,不遵循常规扩容规则。

vector 的扩容不是“按需分配一点”,而是每次触发就重新申请一块更大的连续内存,把旧数据搬过去再释放旧空间——这个过程会导致所有迭代器、指针和引用失效,且开销不小。
vector 什么时候会扩容
扩容只在插入操作导致 size() == capacity() 时发生,典型场景包括:
-
push_back()插入新元素时容量已满 -
insert()在非尾部位置插入,且插入后总元素数超过当前容量 -
resize(n)将大小设为大于当前capacity()的值
注意:reserve(n) 不会改变 size(),也不会触发构造;它只是预分配空间,不调用元素的构造函数。而 resize(n) 会调整 size(),必要时还会默认构造新元素。
扩容因子到底是多少
没有标准规定,完全取决于 STL 实现:
-
libstdc++(GCC 默认):通常用 2 倍,比如容量从 4 → 8 → 16 -
libc++(Clang 默认):常用 1.5 倍,比如 4 → 6 → 9 → 13 - MSVC STL:早期版本用 1.5,新版趋向 2 倍,但行为可能随版本微调
你可以用简单循环实测:
std::vector<int> v; for (int i = 0; i <p>输出序列就能反推出你当前编译器用的是哪种策略。</p> <h3>为什么不能靠扩容来“省事”</h3> <p>频繁扩容不只是慢,还隐含三重代价:</p> <ul> <li> <strong>内存碎片风险</strong>:多次小规模扩容后释放的旧内存块可能无法被后续大块分配复用</li> <li> <strong>移动/拷贝开销</strong>:每个已有元素都要调用移动构造或拷贝构造,对复杂类型(如 <code>std::string</code>、自定义类)尤其明显</li> <li> <strong>迭代器失效不可逆</strong>:一旦扩容,所有指向该 vector 的 <code>iterator</code>、<code>const_iterator</code>、<code>data()</code> 返回的指针、甚至 <code>&v[0]</code> 都变成悬垂指针</li> </ul> <p>所以工程中,如果你知道最终大概要存多少个元素(比如解析一个已知长度的 JSON 数组),直接 <code>v.reserve(expected_count)</code> 是最便宜的预防手段。</p> <h3>vector<bool> 是个特例</bool> </h3> <p>它不是真正的容器,而是一个位域代理类(bit proxy)。它的 <code>operator[]</code> 返回的是临时 <code>std::vector<bool>::reference</bool></code> 对象,不是 <code>bool&</code>;它也不满足 “连续存储” 这一 vector 核心契约;<code>data()</code> 甚至不可用。因此它不遵循上述任何扩容逻辑——它压根就没有传统意义上的 capacity 或 data 指针。别把它当普通 vector 用,尤其别传给期望 <code>bool*</code> 的 C 接口。</p></int>
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











