在使用 vector 容器时,我们除了调用 size() 查看里面有几个元素之外,还会遇到一个常跟它一起出现的成员函数 capacity()。
很多初学的小伙伴容易把 “元素数量(size)” 和 “底层容量(capacity)” 混为一谈。在 C++ 中,与 vector 大小和容量相关的常用成员函数如下表所示。
| 函数 | 说明 | 是否改变元素数量 |
|---|---|---|
| size() | 获取当前实际存放的元素个数 | 否 |
| capacity() | 获取重新分配内存前最多能容纳的元素个数 | 否 |
| reserve(n) | 提前预留至少容纳 n 个元素的底层容量 | 否(只改变 capacity) |
| resize(n) | 将实际元素数量调整为 n | 是(直接改变 size) |
| shrink_to_fit() | 释放多余的空闲容量,使 capacity 贴合 size | 否(只缩减 capacity) |
size() 与 capacity() 有什么区别?
这两个概念放在一起对比其实很好理解。你可以想象一间教室里一共摆放了 50 张桌子,但目前只坐了 30 名学生。
这里的 30 就是 size(),代表当前实际已经存放了多少个元素。而 50 就是 capacity(),代表当前这块内存最多可以容纳多少个元素,如下图所示。

看到这里,可能有些小伙伴会问:“为什么 vector 不干脆有几个元素就只申请几个位置,而要提前多准备一些容量呢?”
这是因为 vector 的元素在内存中必须是连续存放的。如果每次调用 push_back() 添加元素时都重新申请一块更大的内存,再把原有元素一个个搬过去,程序运行就会变得很慢。
因此,当现有空间装满时,vector 会自动成倍扩充底层容量,留出一些空位供后续快速放入数据。
示例 1:观察自动扩容过程
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
for (int i = 1; i <= 4; i++) {
v.push_back(i * 10);
std::cout << "size=" << v.size() << ", ";
std::cout << "capacity=" << v.capacity() << '\n';
}
return 0;
}运行结果如下。
size=1, capacity=1
size=2, capacity=2
size=3, capacity=4
size=4, capacity=4分析:
在这个例子中,我们通过循环依次向空容器中添加 4 个整数。存入前 2 个元素时,size() 和 capacity() 同步增加到了 2。
当存入第 3 个元素时,原来的 2 个位置已经不够用了,于是 vector 自动申请了一块能容纳 4 个元素的新内存。此时 size() 是 3,而 capacity() 变成了 4,多出来的 1 个空位刚好直接供第 4 个元素使用,无需再次扩容。
不同编译器的自动扩容倍数略有差异(如 GCC 通常按 2 倍扩容,MSVC 通常按 1.5 倍扩容),但 capacity() 始终大于或等于 size()。因此在对容器做循环遍历或按下标访问元素时,有效下标范围永远只看 size()。
注意 size() 代表真实存在的元素个数,而 capacity() 只是底层准备好的容量。千万不要因为存入第 3 个元素后 capacity() 变成了 4 就提前去访问 v[3],预留的空位上还没有存放真实元素,直接访问会导致下标越界。
预留容量:reserve()
既然 vector 在容量不够时会自动重新分配内存并搬移元素,那如果我们提前就知道接下来大概要装入 100 个元素,能不能让它一次性把 100 个空位直接准备好呢?这时我们就可以使用 reserve() 成员函数,其中 reserve 是 “预留” 的意思。
语法:
容器名.reserve(n);说明:
调用 reserve(n) 会通知容器提前把底层容量扩充到至少能容纳 n 个元素。如果传入的 n 小于或等于当前的 capacity(),容器什么也不会做,不会把已有容量改小。
这里初学者最容易踩坑的地方是:reserve(n) 只负责 “往教室里提前搬入空桌子”,并不会创建任何真实元素,因此调用后 size() 不会发生改变。
示例 2:使用 reserve() 预留容量
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
v.reserve(10); // 提前预留 10 个元素的容量
std::cout << "预留后 size:" << v.size() << '\n';
std::cout << "预留后 capacity:" << v.capacity() << '\n';
v.push_back(15);
v.push_back(25);
std::cout << "添加后 size:" << v.size() << '\n';
std::cout << "添加后 capacity:" << v.capacity() << '\n';
return 0;
}运行结果如下。
预留后 size:0
预留后 capacity:10
添加后 size:2
添加后 capacity:10分析:
执行 v.reserve(10); 之后,底层容量 capacity() 直接变成了 10,但此时还没有放入数据,所以 v.size() 依然是 0。随后我们添加 2 个元素时,由于不超过预留容量,capacity() 保持 10 不变,size() 变成了 2。
正因为 reserve(10) 没有创建真实元素,刚调用完时 v.size() 依然为 0。此时不能直接使用下标赋值,而应该通过 push_back() 添加数据。
std::vector<int> v;
v.reserve(10);
// 正确方式
v.push_back(15);
// 错误方式
v[0] = 15;调整元素数量:resize()
与只准备空位的 reserve() 不同,resize() 是真正用来修改容器中 “实际元素数量” 的成员函数。
语法:
容器名.resize(n);
容器名.resize(n, 初始值);说明:
调用 resize(n) 时,容器会根据目标数量 n 与当前 size() 的大小关系自动执行 “多删少补”:
- 扩大元素数量:当
n大于当前size()时,会在末尾自动补齐新元素。如果不传第 2 个参数,数值元素默认补0;如果传了第 2 个参数,则统一补为该初始值。 - 缩小元素数量:当
n小于当前size()时,只保留前n个元素,把末尾多出来的元素直接删掉。
示例 3:扩大与缩小元素数量
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {10, 20};
v.resize(5, 99); // 扩大到 5 个元素
std::cout << "扩大后(size=" << v.size() << "):";
for (int x : v) {
std::cout << x << ' ';
}
std::cout << '\n';
v.resize(3); // 缩小到 3 个元素
std::cout << "缩小后(size=" << v.size() << "):";
for (int x : v) {
std::cout << x << ' ';
}
std::cout << '\n';
return 0;
}运行结果如下。
扩大后(size=5):10 20 99 99 99
缩小后(size=3):10 20 99分析:
在这个例子中,v 一开始只有 10 和 20 两个元素,两次调整的过程如下:
- 第 1 次调整:执行
v.resize(5, 99);后,程序保留原有的 10 和 20,并在末尾补上 3 个值为 99 的真实元素。此时v.size()变成 5,我们可以直接通过下标 0 到 4 访问它们。 - 第 2 次调整:执行
v.resize(3);后,容器只保留前 3 个元素,直接删掉末尾多出来的两个 99,v.size()随之变成 3。
释放多余容量:shrink_to_fit()
当调用 clear() 清空元素,或者删除大量元素之后,vector 的实际元素数量 size() 会变小,但它底层已经申请好的容量 capacity() 并不会自动缩减回去。
如果我们在清空或缩减容器之后,确定不再需要那么大的内存了,可以调用 C++11 提供的 shrink_to_fit() 函数,请求容器释放多余的空闲容量。其中 shrink_to_fit 就是 “缩减到恰好合适” 的意思,平时较少用到,这里简单了解一下即可。
语法:
容器名.shrink_to_fit();说明:
调用该函数后,主流编译器通常会把底层容量 capacity() 缩减到与当前的实际元素数量 size() 一致。
示例 4:释放多余的空闲容量
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
v.reserve(100);
v.push_back(10);
v.push_back(20);
v.clear(); // 清空所有元素
std::cout << "clear 后 capacity:" << v.capacity() << '\n';
v.shrink_to_fit(); // 释放多余空闲容量
std::cout << "释放后 capacity:" << v.capacity() << '\n';
return 0;
}运行结果如下。
clear 后 capacity:100
释放后 capacity:0分析:
执行 v.clear(); 之后,虽然元素已经清空,但之前预留的 100 个容量依然保留着。紧接着我们调用 v.shrink_to_fit();,容器就会把这部分闲置内存释放归还,capacity() 也随之降回了 0。
reserve() 与 resize() 的区别
reserve() 和 resize() 名字长得很像,小伙伴们在实际开发中只需要看自己想不想马上创建出 “真实元素”:
reserve(n):只准备空位、不创建元素。调用后只把底层 capacity() 扩大到至少 n,实际元素数量 size() 不变,后续我们仍需通过 push_back() 往里添加数据。
resize(n):直接改变真实元素个数。调用后 size() 直接变成 n,如果比原来大就会自动补齐默认元素,我们可以直接使用下标读写。
