在C++标准库中,vector是最基础且使用频率最高的序列式容器之一。作为动态数组的封装实现,vector完美平衡了内存效率与操作便利性。与原生数组相比,vector的自动内存管理特性使其成为现代C++开发的首选存储结构。
vector的核心优势体现在三个方面:首先是内存连续性,所有元素在内存中紧密排列,这使得迭代访问速度接近原生数组;其次是动态扩展能力,当现有容量不足时,vector会自动申请更大的内存空间并迁移数据;最后是丰富的接口函数,提供了包括插入删除、容量管理、迭代器支持等完整操作集。
关键特性:vector的扩容策略通常采用几何增长模式(如VS编译器默认1.5倍,GCC默认2倍),这种设计使得多次插入的均摊时间复杂度为O(1)
vector提供六种标准构造方式:
cpp复制vector<int> v1; // 默认构造
vector<int> v2(10); // 指定大小构造
vector<int> v3(10, 5); // 指定大小和初始值
vector<int> v4(v3.begin(), v3.end()); // 迭代器范围构造
vector<int> v5 = {1,2,3}; // 初始化列表构造(C++11)
vector<int> v6(v5); // 拷贝构造
初始化方式的选择直接影响代码效率。对于已知元素值的情况,初始化列表是最简洁高效的选择;而需要预分配空间时,指定大小的构造方式能避免后续多次扩容。
vector提供五种元素访问方式,各有适用场景:
operator[]:最常用的随机访问方式,不进行边界检查at():带边界检查的安全访问,越界抛出std::out_of_range异常front()/back():高效访问首尾元素data()(C++11):获取底层数组指针,用于需要裸指针的场景cpp复制vector<int> vec{10,20,30};
cout << vec[1]; // 20 (快速访问)
cout << vec.at(2); // 30 (安全访问)
int* p = vec.data(); // 获取底层数组指针
容量相关接口是vector高效使用的关键:
size():当前元素数量capacity():当前分配的内存容量reserve(n):预分配至少n个元素的空间shrink_to_fit()(C++11):请求移除未使用的容量典型容量优化策略:
cpp复制vector<int> vec;
vec.reserve(1000); // 预分配避免多次扩容
for(int i=0; i<1000; ++i) {
vec.push_back(i);
}
vec.shrink_to_fit(); // 释放多余空间
vector的核心修改操作包括:
push_back()/pop_back():尾部操作,时间复杂度O(1)insert():任意位置插入,时间复杂度O(n)erase():删除元素,可能导致元素移动clear():清空元素但不释放内存emplace_back()(C++11):原地构造,避免临时对象插入操作效率对比:
cpp复制vector<string> vec;
vec.push_back(string("temp")); // 需要构造临时对象
vec.emplace_back("temp"); // 直接在容器内构造
vector提供完整的迭代器支持:
begin()/end():获取首尾迭代器rbegin()/rend():反向迭代器cbegin()/cend()(C++11):常量迭代器迭代器失效规则:
vector与STL算法完美配合:
cpp复制vector<int> vec{5,3,8,1,9};
sort(vec.begin(), vec.end()); // 排序
auto it = find(vec.begin(), vec.end(), 8); // 查找
accumulate(vec.begin(), vec.end(), 0); // 累加
通过reserve()预分配空间可以显著提升性能:
cpp复制// 低效写法
vector<int> vec;
for(int i=0; i<1e6; ++i) {
vec.push_back(i); // 可能触发多次扩容
}
// 高效写法
vector<int> vec;
vec.reserve(1e6); // 一次性分配
for(int i=0; i<1e6; ++i) {
vec.push_back(i);
}
C++11引入的移动语义大幅提升vector性能:
cpp复制vector<string> vec;
string largeStr = getLargeString();
vec.push_back(std::move(largeStr)); // 移动而非拷贝
高效删除元素的惯用法:
cpp复制// 删除特定条件元素(如删除所有奇数)
vector<int> vec{1,2,3,4,5};
vec.erase(
remove_if(vec.begin(), vec.end(),
[](int x){return x%2!=0;}),
vec.end()
);
常见失效场景及解决方案:
cpp复制vector<int> vec{1,2,3,4,5};
auto it = vec.begin() + 2;
vec.insert(it, 10); // it可能失效
// 正确做法:重新获取迭代器
it = vec.begin() + 2;
vector不会自动收缩容量,需要主动管理:
cpp复制vector<int> vec(1000);
vec.resize(10); // size减小但capacity不变
vector<int>(vec).swap(vec); // 传统收缩方法
vec.shrink_to_fit(); // C++11标准方法
多维数组的两种实现方式对比:
cpp复制// 方式1:vector嵌套
vector<vector<int>> mat(10, vector<int>(20));
// 方式2:单vector模拟
vector<int> mat(10*20); // 更高效但使用稍复杂
C++11后vector支持移动构造和移动赋值:
cpp复制vector<string> createVector() {
vector<string> v{"a", "b", "c"};
return v; // 触发移动语义
}
auto vec = createVector(); // 高效转移所有权
C++11统一初始化语法:
cpp复制vector<int> vec{1,2,3}; // 初始化列表
vec = {4,5,6}; // 列表赋值
C++20新增的便捷操作:
cpp复制vector<int> vec;
std::erase(vec, 3); // 删除所有值为3的元素
std::erase_if(vec, [](int x){return x>5;});
在实际工程中,vector的性能表现往往取决于使用方式。根据我的经验,在数据规模超过1万元素时,合理的预分配和算法选择可能带来10倍以上的性能差异。特别是在高频交易、游戏开发等对性能敏感的领域,vector的微优化常常能带来显著效果。