系列文章目录
C++入门
C++类和对象(上)
C++类和对象(中)
C++类和对象(下)
C/C++内存管理
C++string类
一、vector是什么?
vector是表示可变大小数组的序列容器,类似于数组,vector也采用连续的存储空间来存储元素。这就意味之可以通过下标对vector中元素进行随机访问。同时,其大小是可以动态改变的,会被容器自动处理。
本质上讲,vector使用动态内存分配数组来存储它的元素。当新元素插入时,这个数组需要被重新分配大小。其做法是,分配一个新的数组,将全部元素移到这个数组。就时间而言,这是一个代价相对较高的任务。
vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大,但是获得了管理存储空间的能力。而对于不同的库则采用不同的策略权衡空间的使用和重新分配。
二、常用接口说明
1.常见的构造函数
constructor构造函数声明 | 接口说明 |
---|
vector | 无参构造 | vector(size_t n, const value_type& val = value_type()) | 构造并初始化n个val | vector(const vector& x) | 拷贝构造 | vector InputIterator first, InputIterator last | 使用迭代器进行初始化构造 |
代码如下:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> first;
vector<int> second(4, 100);
vector<int> third(second.begin(), second.end());
vector<int> fourth(third);
return 0;
}
2.vector iterator的使用
iterator使用 | 接口说明 |
---|
begin + end | 获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator | rbegin + rend | 获取最后一个数据位置的reverse_iterator,获取第一个数据钱一个位置的iterator |
注意:begin获取的是第一个位置rbegin获取的是倒数第一个位置,而end获取的是最后一个位置的下一个位置,rend获取的是第一个位置的前一个位置。
代码如下:
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << ' ';
cout << endl;
++it;
}
cout << endl;
vector<int>::reverse_iterator rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
cout << endl;
++rit;
}
return 0;
}
3.关于vector的容量
容量空间 | 接口说明 |
---|
size | 获取数据个数 | capacity | 获取容量大小 | empty | 判空 | resize | 改变vector的size | reserve | 改变vector的capacity |
reserve只负责开辟空间,如果确定知道需要多少空间reserve可以缓解vector增容的代价缺陷问题。
resize在开辟空间时还会进行初始化,影响size。
4.vector的增删改查
vector | 接口说明 |
---|
push_back | 尾插 | pop_back | 尾删 | find | 查找(算法) | insert | 在指定位置之前插入数据 | erase | 删除指定位置的数据 | swap | 交换两个vector的数据空间 | operator[] | 像数组一样随机访问 |
代码如下:
尾插四个数据并用迭代器打印:
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << ' ';
cout << endl;
++it;
}
return 0;
}
尾删两个数据:
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.pop_back();
v.pop_back();
return 0;
}
在指定范围内查找相应数据,并进行插入和删除操作。
int main()
{
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
v.insert(pos, 30);
PrintVector(v);
pos = find(v.begin(), v.end(), 3);
v.erase(pos);
PrintVector(v);
return 0;
}
5.迭代器失效
我们首先来看一段代码:
int main()
{
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
v.insert(pos, 30);
PrintVector(v);
pos = find(v.begin(), v.end(), 3);
v.erase(pos);
PrintVector(v);
return 0;
}
这个还是上面的插入和删除操作,首先在指定范围内找到3这个整型元素,然后在这个位置插入30,删除也是先在指定范围内找到3这个整型元素,然后在这个位置删除。但是删除的时候我们又重新定义了一个迭代器,如果我们不定义呢?会发生什么?
int main()
{
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
v.insert(pos, 30);
PrintVector(v);
v.erase(pos);
PrintVector(v);
return 0;
}
在vs编译器上程序崩溃了,因为插入数据以后,迭代器的意义发生改变了,根据这个例子来分析,本来我们是让其指向3这个元素的位置,但是插入数据以后,迭代器指向的却是我们新插入的元素。这就是迭代器失效。
因为迭代器的主要作用就是让算法能够不关心底层数据,其实底层就是一个指针,或者说是对指针进行了封装。因此迭代器失效,实际就是迭代器底层对应指针所指向空间销毁了,而使用一块已被释放的内存,造成的后果是程序崩溃(如果继续使用已经失效的迭代器,程序可能就会崩溃)。
而下列操作可能会导致vector迭代器失效:
会引起其底层空间改变的操作,都有可能使迭代器失效,比如resize,reserve,insert,erase,push_back等。
而解决这个问题的办法很简单,只要在使用前对迭代器重新赋值即可。
|