会,但仅在扩容时发生;vector扩容需重新分配内存、拷贝/移动元素并析构旧对象,时间复杂度o(n),若未预估容量在循环中频繁push_back将引发明显性能毛刺;访问和迭代性能与原生数组一致。

会,但只在特定操作和场景下出现;多数日常使用中感知不到,更不会“拖慢整个程序”。
vector扩容时必然触发内存重分配
当push_back导致当前capacity()不足时,vector必须:
- 向堆申请一块更大的内存(GCC 通常翻倍,MSVC 常用 1.5 倍)
- 逐个调用元素的拷贝/移动构造函数,把旧数据搬过去
- 析构旧内存中的对象,并释放那块内存
这个过程是 O(n) 的,且涉及堆分配器调用——比栈上操作慢 2–3 个数量级。如果你在 tight loop 里反复 push_back 且没预估大小,性能毛刺会很明显。
反例:std::vector<:string> lines; while (std::getline(in, s)) lines.push_back(s);</:string> —— 若文件有 10 万行,可能触发 17 次扩容,其中最后一次要拷贝 6.5 万个 std::string 对象。
访问和迭代性能几乎无差别
只要不扩容、不 erase 中间元素,vector 的 operator[]、at()、迭代器遍历,和原生数组 / std::array 完全一致:
- 底层都是连续内存,CPU 缓存友好
- 下标计算是纯加法:
data_ + i,无函数调用开销 - 现代编译器对
vec[i]的优化程度和arr[i]相同
所以像 for (size_t i = 0; i 这种写法,生成的汇编和原生数组几乎一样。
小对象 + 预分配后,vector 和 array 性能基本持平
当你明确知道元素个数(比如解析固定格式的二进制包、预分配图像像素缓冲),用 reserve() 或 resize() 后,vector 就退化为“堆上的静态数组”:
-
std::vector<int> buf; buf.resize(1024);</int>→ 内存一次分配,后续所有读写都不触发任何额外逻辑 - 此时与
std::array<int></int>的唯一区别只剩内存位置(堆 vs 栈)和析构时机 - 对于
int、float等 trivial 类型,二者 benchmark 差距通常在 ±3% 以内
真正拉开差距的是:栈空间有限,std::array<char></char> 可能直接栈溢出,而 vector 不会。
容易被忽略的隐性开销点
这些地方不常被测试,但线上服务或嵌入式环境里容易暴露:
-
clear()不释放内存 ——capacity()保持不变,下次复用虽快,但长期驻留大容量会撑高 RSS 内存占用 - 频繁创建销毁小 vector(如函数局部变量)→ 每次都走堆分配器,比
std::array多出微秒级延迟 - 含非 trivial 析构函数的对象(如
std::string、自定义类)在扩容/erase 时,拷贝/移动/析构成本不可忽略
如果你在循环里写 std::vector<:string> tmp; tmp.push_back(...);</:string>,就等于每轮都 malloc + 构造 + free + 析构 —— 这才是真瓶颈,不是 vector 本身,而是用法。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











