c++oding="utf-8" ?>
std::vector与原生数组性能差异极小,但关键区别在于隐性开销:vector扩容(o(n)拷贝、堆碎片)和原生数组栈溢出崩溃;reserve预分配可消除扩容代价,大数组须避免栈分配。

std::vector 和原生数组(int arr[100] 这类)在绝大多数场景下性能差异极小,但关键区别不在“谁更快”,而在于“谁在什么条件下会突然变慢”——尤其是 std::vector 的扩容行为会带来隐性开销,而原生数组一旦栈溢出就直接崩溃。
std::vector push_back 触发扩容时的实际代价
每次 push_back 超出当前 capacity(),std::vector 就必须:分配新内存 → 逐个拷贝/移动旧元素 → 释放旧内存。这个过程不是 O(1),而是 O(n) 操作,且伴随堆内存碎片风险。
- GCC(libstdc++)默认按 2 倍扩容,比如从容量 64 扩到 128,意味着要拷贝 64 个对象;若对象是带深拷贝的类(如
std::string),开销更大 - 连续多次未预分配的
push_back可能触发多轮扩容,总拷贝量接近 2n —— 即插入 n 个元素,实际搬运内存约 2n 次 - 用
reserve(n)预分配后,后续 n 次push_back全部是纯写入,无拷贝、无重分配
原生数组栈溢出的静默陷阱
声明像 int arr[1000000] 这样的大数组,编译能过,运行大概率段错误(SIGSEGV)。Linux 默认线程栈大小通常为 8MB,100 万个 int 就占 4MB;再叠加函数调用帧,极易越界。
- 错误现象:
Segmentation fault (core dumped),gdb 回溯常停在函数入口,不提示数组问题 - 安全做法:大尺寸固定数组必须用
new int[1000000]或std::array(但后者同样栈分配,不能过大) -
std::array本质仍是栈分配,只是加了 STL 接口包装;它不解决栈空间限制,只解决裸数组的类型安全和接口缺失问题
随机访问性能几乎无差别,但边界检查可关闭
两者都支持 operator[],底层都是指针偏移,汇编级指令一致。真正影响实测性能的,往往是是否启用边界检查。
-
std::vector::at()永远做范围检查,抛异常,开销不可忽略;operator[]不检查,和原生数组一样快 - 原生数组完全无检查,越界即 UB(未定义行为),可能静默读错数据或崩溃
- Clang/GCC 在 -O2 下会对
vector[i]做和数组一样的优化,只要索引确定、无别名冲突
真正容易被忽略的点是:性能对比必须绑定具体操作模式。只比“读第 5 个元素”毫无意义;要看你是在初始化阶段批量填充、还是运行时动态增删、或是嵌入 tight loop 做数值计算——每种模式下,std::vector 和原生数组的瓶颈根本不在同一位置。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











