C++ vector的使用
目录
一、vector简介
二、vector的使用
三、vector的空间增长问题
reserve和resize
四、vector的迭代器使用
begin和end
rbegin和rend
五、vector的增删查改
push_back和pop_back
insert和erase
find函数
六、元素访问
七、vector迭代器失效问题
迭代器失效解决方法
一、vector简介
STL 中的 vector
是 C++ 标准库中最核心的动态数组容器,用于替代原始数组,提供自动内存管理和丰富功能。
核心接口速查
// 构造
vector<int> vec; // 空vector
vector<int> vec(100); // 100个0
vector<int> vec(100, 5); // 100个5// 元素访问
vec[0] = 10; // 无边界检查
vec.at(0) = 10; // 带边界检查(越界抛异常)
int* p = vec.data(); // 获取底层数组指针// 容量操作
vec.reserve(1000); // 预分配内存(不初始化)
vec.resize(50); // 改变元素数量
vec.shrink_to_fit(); // 释放多余内存// 增删元素
vec.push_back(10); // 尾部插入
vec.pop_back(); // 尾部删除
vec.insert(vec.begin()+2, 20); // 指定位置插入
vec.erase(vec.begin()+1); // 删除指定位置// 工具函数
vec.empty(); // 是否为空
vec.size(); // 实际元素数量
vec.capacity(); // 当前内存容量
vector是 STL 中综合性能最优的通用容器,适用于 >90% 需动态数组的场景。其核心优势在于随机访问性能 + 缓存局部性 + 自动内存管理,是现代 C++ 高性能编程的基础设施。
二、vector的使用
构造
1: 构造一个某类型的空容器。
vector<int> vec; // 空vector
2: 构造一个含有n个val的某类型容器。
vector<int> vec(100, 5); // 100个5
3:拷贝构造
vector<int> v3(v2); //拷贝构造int类型的v2容器的复制品
4:使用迭代器拷贝构造某一段内容
vector<int> v4(v2.begin(), v2.end()); //使用迭代器拷贝构造v2容器的某一段内容
vector存储的类型很多也可以是自定义类型
int main()
{vector<string> vstr; //数组里存放的是string类string s1 = "张三"; vstr.push_back(s1);vstr.push_back("李四"); //隐式类型转换return 0;
}
三、vector的空间增长问题
容量空间 | 接口说明 |
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
reserve(重点) | 改变vector的capacity |
resize(重点) | 改变vector的size |
size和capacity
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> vec(100, 5);cout << vec.size() << endl; //获取当前容器中的有效元素个数cout << vec.capacity() << endl; //获取当前容器的最大容量return 0;
}
reserve和resize
通过reserse函数改变容器的最大容量,resize函数改变容器中的有效元素个数。
reserve规则:
1、当所给值大于容器当前的capacity时,将capacity扩大到该值。
2、当所给值小于容器当前的capacity时,什么也不做。
resize规则:
1、当所给值大于容器当前的size时,将size扩大到该值,扩大的元素为第二个所给值,若未给出,则默认为0。
2、当所给值小于容器当前的size时,将size缩小到该值。
#include<iostream>
#include<vector>
using namespace std;int main()
{vector<int> v(5, 2);cout << v.size() << endl; //5cout << v.capacity() << endl; //5v.reserve(10); //改变容器的capacity为10,size不变cout << v.size() << endl; //5cout << v.capacity() << endl; //10v.resize(8); //改变容器的size为8cout << v.size() << endl; //8cout << v.capacity() << endl; //10return 0;
}
empty
通过empty函数判断当前容器(size)是否为空。
int main()
{vector<int> vec(10, 2);cout << vec.empty() << endl;//0 非空vector<int> v;cout << v.empty() << endl;//1 空return 0;
}
四、vector的迭代器使用
vector iterator 的使用
iterator的使用 | 接口说明 |
begin() | 获取第一个数据位置的iterator/const_iterator |
end() | 获取最后一个数据的下 一个位置的iterator/const_iterator |
rbegin | 获取最后一个数据位置的reverse_iterator |
rend() | 获取第一个数据前一个位置的reverse_iterator |
begin和end
通过begin函数可以得到容器中第一个元素的正向迭代器,通过end函数可以得到容器中最后一个元素的后一个位置的正向迭代器
int main()
{vector<int> v(10, 2);//正向迭代器遍历容器vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;//2 2 2 2 2 2 2 2 2 2return 0;
}
rbegin和rend
通过rbegin函数可以得到容器中最后一个元素的反向迭代器,通过rend函数可以得到容器中第一个元素的前一个位置的反向迭代器。
int main()
{vector<int> v{0,1,2,3,4,5,6,7,8,9};for (int i = 0; i < 10; i++){v.push_back(i);}//反向迭代器遍历容器vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";//9 8 7 6 5 4 3 2 1 0rit++;}cout << endl;return 0;
}
五、vector的增删查改
push_back和pop_back
通过push_back函数对容器进行尾插,pop_back函数对容器进行尾删。
int mian()
{vector<int> v{ 0,1,2,3,4};for (int i = 0; i < 10; i++){v.push_back(i);}v.pop_back();v.pop_back();//v 0 1 2return 0;
}
insert和erase
insert函数通过在指定位置的元素之前插入新元素来扩展向量,从而有效地将容器大小增加插入的元素数量。
通过erase函数可以删除所给迭代器位置的元素,或删除所给迭代器区间内的所有元素。
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//insert (iterator position, const value_type& val);v.insert(v.end(), 0); //在容器尾插入0//insert(iterator position, size_type n, const value_type & val);v.insert(v.begin(), 5, -1); //在容器开头插入5个-1//erase (iterator position);v.erase(v.begin()); //删除容器中的第一个元素//erase (iterator first, iterator last);v.erase(v.begin(), v.begin() + 5); //删除在该迭代器区间内的元素(左闭右开)return 0;
}
find函数
template <class InputIterator, class T>InputIterator find (InputIterator first, InputIterator last, const T& val);
find函数共三个参数,前两个参数确定一个迭代器区间(左闭右开),第三个参数确定所要寻找的值。
find函数在所给迭代器区间寻找第一个匹配的元素,并返回它的迭代器,若未找到,则返回所给的第二个参数。
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator pos = find(v.begin(), v.end(), 2); //获取值为2的元素的迭代器v.insert(pos, 10); //在2的位置插入10//1 10 2 3 4pos = find(v.begin(), v.end(), 3); //获取值为3的元素的迭代器v.erase(pos); //删除3//1 2 10 4return 0;
}
六、元素访问
vector当中实现了 [ ] 操作符的重载,因此我们也可以通过“下标+[ ]”的方式对容器当中的元素进行访问。
int main()
{vector<int> v(10, 1);//使用“下标+[]”的方式遍历容器for (size_t i = 0; i < v.size(); i++){v[i] = i;cout << v[i] << " ";}cout << endl;return 0;
}
七、vector迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对 指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器 底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即 如果继续使用已经失效的迭代器,程序可能会崩溃)。
1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、 assign、push_back等。
#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可。*/while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
迭代器失效解决方法
使用迭代器时,永远记住一句话:每次使用前,对迭代器进行重新赋值。
int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();v.assign(100, 8);//这里重新定位了it让其指向新空间的起始it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}