1. 为什么我们需要vector
在C++的世界里,数组是最基础的数据结构,但原生数组有个致命缺陷——它的大小必须在编译时就确定下来。想象你正在开发一个学生管理系统,你根本无法预知学校明年会招多少新生。这时候vector就派上用场了,它就像个会自己长大的智能数组,完全解决了这个痛点。
我十年前刚接触vector时,最震撼的就是它的自动扩容机制。当时我手动实现了一个动态数组,光是处理扩容逻辑就写了上百行代码,还各种内存泄漏。vector把这些脏活累活都封装好了,我们只需要关注业务逻辑就行。
vector属于STL(标准模板库)中的序列容器,底层实现通常采用动态数组。和array相比,它的最大优势就是动态大小;和list相比,它在随机访问时性能更好(O(1)复杂度)。不过要注意,vector在中间插入/删除元素时效率较低,这是由它的内存布局特性决定的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. vector的核心操作全解析
2.1 创建和初始化vector
创建vector至少有五种常用方式,每种都有其适用场景:
cpp复制// 空vector
vector<int> v1;
// 指定初始大小(10个0)
vector<int> v2(10);
// 指定大小和初始值(5个42)
vector<int> v3(5, 42);
// 用数组初始化
int arr[] = {1,3,5,7};
vector<int> v4(arr, arr+4);
// C++11初始化列表
vector<int> v5 = {9,8,7,6};
重要提示:使用reserve()预分配空间可以避免频繁扩容带来的性能损耗。比如你知道要存约1000个元素,可以先v.reserve(1000)。
2.2 元素访问的陷阱与技巧
访问vector元素看似简单,但坑可不少:
cpp复制vector<string> names = {"Alice", "Bob"};
// 安全的访问方式
cout << names[0]; // 不检查越界
cout << names.at(1); // 会检查越界,越界抛异常
// 危险的访问
cout << names[2]; // 未定义行为!
cout << names.at(2); // 抛出std::out_of_range
我曾在项目中使用[]操作符导致程序随机崩溃,花了整整两天才找到是越界访问的问题。现在我的原则是:在调试阶段尽量用at(),发布时再考虑改用[]提升性能。
2.3 增删元素的高效姿势
vector的尾部操作是O(1)复杂度,但中间操作可能引发元素大搬家:
cpp复制vector<int> nums = {1,2,3};
// 高效操作(尾部)
num
