markdown复制## 1. vector容器基础认知
作为C++标准模板库(STL)中最常用的序列式容器,vector本质上是一个动态数组的封装。与普通数组最大的区别在于其"按需自动扩容"的特性——当元素数量超过当前容量时,会自动申请更大的内存空间并将原有数据迁移过去。这种设计使得开发者无需手动管理内存,同时又能获得接近原生数组的访问效率。
在实际工程中,vector常用于以下场景:
- 需要频繁在尾部增删数据(时间复杂度O(1))
- 需要随机访问元素(时间复杂度O(1))
- 元素总量无法预先确定
- 需要与其他STL算法配合使用
> 注意:虽然vector支持中间插入操作,但效率较低(时间复杂度O(n)),此类场景建议考虑list容器
## 2. vector核心操作详解
### 2.1 初始化方式对比
```cpp
// 空vector
vector<int> v1;
// 预分配10个元素空间(容量为10,但size仍为0)
vector<int> v2(10);
// 初始化10个值为5的元素
vector<int> v3(10, 5);
// 通过初始化列表
vector<int> v4 = {1, 2, 3};
// 通过数组指针范围
int arr[] = {1, 2, 3};
vector<int> v5(arr, arr + sizeof(arr)/sizeof(int));
不同初始化方式的选用原则:
cpp复制vector<int> vec = {10, 20, 30};
// 安全访问(推荐)
cout << vec.at(1); // 20
try {
cout << vec.at(5); // 抛出out_of_range异常
} catch(const exception& e) {
cerr << e.what();
}
// 不安全但高效的访问
cout << vec[1]; // 20
cout << vec[5]; // 未定义行为!
// 首尾元素快捷访问
cout << vec.front(); // 10
cout << vec.back(); // 30
关键经验:生产环境优先使用at()而非operator[],虽然性能略低但安全性更高。调试阶段可以使用_GLIBCXX_DEBUG宏开启边界检查。
cpp复制vector<int> vec;
// 当前元素数量
cout << vec.size(); // 0
// 当前分配的内存容量
cout << vec.capacity(); // 实现定义,可能是0
vec.push_back(1);
cout << vec.capacity(); // 可能变为1
vec.reserve(100); // 预分配100个元素空间
cout << vec.capacity(); // 100
cout << vec.size(); // 仍为1
扩容策略的工程实践:
cpp复制vector<int> vec = {1, 2, 3, 4};
auto it = vec.begin() + 2;
vec.push_back(5); // 可能导致迭代器失效!
cout << *it; // 未定义行为
迭代器失效的典型场景:
安全实践方案:
cpp复制// 方案1:操作后重新获取迭代器
it = vec.begin() + 2;
// 方案2:使用索引替代迭代器
size_t pos = 2;
vec.erase(vec.begin() + pos);
cpp复制vector<int> vec = {5, 3, 1, 4, 2};
// 排序
sort(vec.begin(), vec.end()); // 1,2,3,4,5
// 查找
auto it = find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
cout << "Found at position: " << distance(vec.begin(), it);
}
// 逆序
reverse(vec.begin(), vec.end()); // 5,4,3,2,1
// 遍历(C++11起推荐方式)
for (int num : vec) {
cout << num << " ";
}
对于小型POD类型:
cpp复制struct Point { int x, y; };
vector<Point> points; // 内存连续,访问高效
对于大型对象:
cpp复制class BigObject { /* 大量数据成员 */ };
vector<unique_ptr<BigObject>> objVec; // 存储指针减少拷贝开销
批量插入优化:
cpp复制// 低效方式(多次扩容)
for (int i = 0; i < 10000; ++i) {
vec.push_back(i);
}
// 高效方式
vec.reserve(10000);
for (int i = 0; i < 10000; ++i) {
vec.push_back(i);
}
// 最优方式(C++11起)
vec.insert(vec.end(), {/*初始化列表*/});
移动语义应用(C++11):
cpp复制vector<string> vec;
string str = "large string";
vec.push_back(move(str)); // 转移所有权,避免拷贝
交换技巧清空vector:
cpp复制vector<int> vec(10000);
vector<int>().swap(vec); // 立即释放内存
cout << vec.capacity(); // 0
自定义分配器示例:
cpp复制template<typename T>
class MyAllocator { /* 实现分配器接口 */ };
vector<int, MyAllocator<int>> customVec; // 使用自定义内存管理
现象:程序崩溃于vector操作
排查步骤:
现象:push_back操作变慢
优化方案:
cpp复制vector<pair<int, string>> vec;
vec.emplace_back(1, "test"); // 直接构造,避免临时对象
常见差异点:
兼容性写法:
cpp复制#if defined(_MSC_VER)
vec.reserve(1000); // 针对VS优化
#endif
接口设计原则:
线程安全策略:
替代方案选型:
现代C++特性:
cpp复制// C++20起可以
constexpr vector<int> compileTimeVec = {1, 2, 3};