STL标准库之vector
- vector类的简介
- 常用的vector类的接口
- 构造
- 容量
- 遍历及访问
- 增删查改
- 迭代器
- 迭代器失效问题
vector类的简介
vector是大小可变数组的序列容器,与string相比,vector中可以存任何类型的数据,而string中存储的只能是字符类型。
因为vector采用的是连续存储空间,因此它也可以通过下标对vector中的元素进行访问,而它比数组的优势在于,它的大小是可以动态改变的,它的大小会被容器自动处理。
在插入新元素的时候,并没有使用常规的开辟新数组,拷贝元素,释放旧空间,而是会以空间换取时间的方式,事先多分配一部分空间,以便于未来可能会增加的元素
常用的vector类的接口
构造
函数名称 | 功能 |
---|---|
vector() | 无参构造 |
vector(size_t n, const value_t& val = val_type() ) | 构造并初始化n个val |
vector(const vector& v) | 拷贝构造 |
vector(InputIterator first, InputIterator last) | 使用迭代器进行构造 |
对应写法
vector<int> v();
vector<int> v1(5, 10);
vector<int> v2(v);
vector<int> v3(v1.begin(), v1.begin()+5);
注意:vector是一个类模板,需要在构造时进行类型定义。
而在c++11中,还可以用数组直接进行构造 vector v(1,2,3,4,5);
容量
函数名称 | 功能 |
---|---|
size | 获取元素个数 |
capacity | 获取当前容量大小 |
empty | 判断当前vector是否为空 |
resize | 改变vector中有效元素的个数 |
reserve | 改变容量大小(只增不减) |
当前的容量部分的函数实际上和string的非常相似,但是string在resize中由于内部存在的数组,与vector稍微不同
我们在扩容时,vs下是以1.5倍来扩容的,g++是按2倍来扩容的。如果事先知道vector中大概要存放多少个元素,可以先对其进行扩容,这样就能够避免边插入边扩容的问题了。
遍历及访问
函数名称 | 功能 |
---|---|
operator[] | 访问元素 |
at | 访问元素 |
front | 访问第一个元素 |
back | 访问最后一个元素 |
请注意:访问元素有以下几种访问方式
//auto遍历
for(auto : e : v2)
{
cout << e << " ";
}
cout << endl;
//下标遍历
for (size_t i = 0; i < v1.size(); ++i)
{
cout << v1[i] << " ";
}
cout << endl;
//正向迭代器遍历
auto it = v1.begin();
while (it != v1.end())
{
cout << *(it) << " ";
++it;
}
cout << endl;
//反向迭代器遍历
auto rit = v1.rbegin();
while(rit != v..rend())
{
cout << *(rit) << " ";
++rit;
}
cout << endl;
增删查改
函数名称 | 功能 |
---|---|
push_back | 尾插 |
pop_back | 尾删 |
find | 查找(是算法模块实现的,不是vector的成员函数) |
insert | 在pos前插入val |
erase | 删除pos位置的数据 |
swap | 交换两个vector的数据空间 |
operator[] | 像数组一样通过下标访问 |
迭代器
如当前图片所示:begin是在当前vector中的第一个元素的位置,end在当前vector最后一个元素的下一个位置,而反向迭代器正好相反。
迭代器失效问题
如果我们写这样一个代码
当程序执行到第14行时,直接奔溃了。这是什么原因呢?
实际上和当前这个迭代器有关,当前迭代器我们可以将其理解为是一个指针,当前指针本来指向的是vector的第一个元素的位置,而我们将其扩容后,实际上在底层经历了开辟新空间,拷贝元素,释放旧空间三个步骤,当这三个步骤结束后,原本指向第一个元素的指针已经失去了意义,成为了野指针,我们要访问这个野指针程序就会奔溃。因为我们使用的是一块已经被释放的空间。
如果总结下来:有以下几种情况可能会导致迭代器失效
1.会引起底层空间发生改变的操作:resize,reserve,insert,assign,push_back
2.指定位置删除元素
int main()
{
vector<int> v{1,2,3,4,5,6};
auto pos = find(v.begin(), v.end(), 5);
v.erase(pos);
cout << *(pos) << endl;
return 0;
}
针对上述迭代器失效的解决办法,第一种情况,我们要在使用迭代器之前再次对迭代器进行赋值
第二种情况,我们要在使用erase时去接收返回值。