C++ 的 vector 与 array:用哪个?
先给短答案,再讲面试和真实代码里真正要紧的细节。
十秒答案
默认用 std::vector。只有当"大小是题目的一部分"时才用定长数组(而且用 std::array,不用 C 数组)。后面全在解释为什么 — 因为"就用 vector"这句话扛不住追问。
三种容器,一个思想
| C 数组 | std::array | std::vector | |
|---|---|---|---|
| 大小 | 编译期固定 | 编译期固定 | 运行期可增可减 |
| 住在哪 | 声明处(局部就在栈上) | 声明处 | 数据在堆;对象本身随便放 |
| 知道自己多长吗 | 不知道 — 自己记 | 知道 — .size() | 知道 — .size() |
| 可拷贝? | 不行(退化成指针) | 行 | 行 |
| 传进函数 | 别扭(变指针,长度丢失) | 干净 | 干净 |
| 越界检查 | 无 | .at() 有 | .at() 有,[] 无 |
各自长什么样
#include <array>
#include <vector>
int main() {
int raw[5] = {1, 2, 3, 4, 5}; // C 数组:大小是类型的一部分
std::array<int, 5> fixed = {1, 2, 3, 4, 5}; // 定长,但是真类型
std::vector<int> grow = {1, 2, 3}; // 可变长
grow.push_back(4); // 现在装着 1 2 3 4
return 0;
}
注:浏览器练习场目前覆盖教学核心(iostream、cmath、cstdio……),这类片段请在桌面编译器上跑 — 或等练习场支持容器。
vector 为什么默认赢
- 运行期才知道大小。真实数据大多编译期不知道长度:文件的行、用户的输入、网络消息。vector 会长大;数组不会。
- 它记得自己的长度。裸数组传进函数悄悄退化成指针 — 缓冲区溢出的经典源头。vector 走到哪
.size()跟到哪。 - 它也不慢。vector 的存储和数组一样是一整块连续内存。迭代性能在度过最初的扩容期后通常与数组相同;预知最终大小就先
reserve(n),几乎无代价。 - 它跟谁都合得来 — 范围 for、
std::sort等算法、标准库全家桶。
什么时候定长数组真的更好
- 大小由问题本身定死:一周七天、棋盘 8×8、RGB 三个分量。
- 嵌入式热点循环里要零堆分配 —
std::array永不分配。 - 对象要放栈上且确认很小。
值得备好的面试追问
- "vector 怎么扩容?" 撞到容量时分配更大的块(常见 ~1.5× 或 2×)并把元素搬过去 — 所以反复
push_back依然是摊还 O(1)。 - "vector<bool> 是什么?" — 陷阱题:它是按位打包的特化版本,行为不像普通 vector。
- "
size()和capacity()的区别?" —size()= 在用元素数;capacity()= 下次扩容前已开好的槽位。 - "vector 会让指针失效吗?" — 会:任何扩容或
insert/erase都可能搬走存储。别在修改后保留指向 vector 内部的裸指针/引用。
经验法则
写 std::vector,直到测出不该用的理由。天然定长?用 std::array。裸 C 数组留给与 C 代码交互和极限嵌入式场景 — 即便那时也要包一层。