目录
1. vector的定义
2. 迭代器iterator的使用
3. vector空间增长问题
(1). size与capacity
(2). empty与resize与reserve
4. vector的增删查改
(1) . push_back和pop_back
(2). find与insert与erase
(3). swap与operator[]
5. vector迭代器失效问题
(1). 改变空间
(2). 删除操作导致的失效
std::vector 是C++标准模板库(STL)中的一个非常重要的容器类,它提供了一种动态数组的功能。能够存储相同类型的元素序列,并且可以自动管理存储空间的大小,以适应序列大小变化,处理元素集合的时候很灵活
1. vector的定义
构造函数声明 | 接口说明 |
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;
using std::vector;
using namespace std;
int main()
{
vector<int> v1;
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
vector<int> v2(10);
vector<int> v3(10, 6);
for (size_t i = 0; i < v2.size(); i++)
{
cout << v2[i] << "," << v3[i] << " ";
}
cout << endl;
vector<int> v4(v2);
for (size_t i = 0; i < v4.size(); i++)
{
cout << v4[i] << " ";
}
cout << endl;
vector<int> v5(v3.begin(), v3.begin() + 2);
for (size_t i = 0; i < v5.size(); i++)
{
cout << v5[i] << " ";
}
cout << endl;
}
其中v1是无参默认构造, v2是利用了缺省值全初始化为0,v3是初始化n个 6,v4是用v2进行拷贝构造,v5则是利用迭代器进行构造
输出结果如下
2. 迭代器iterator的使用
iterator的使用 | 接口说明 |
begin+end | 获取第一个位置数据的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator |
rbegin+rend | 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator |
如下图所示
使用代码如下
#include<iostream>
#include<vector>
//using namespace std;
using namespace std;
int main()
{
vector<int> v(10,6);
v.push_back(1);
//vector<int>::iterator it = v.begin();
auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
vector<int>::reverse_iterator iv = v.rbegin();
while (iv != v.rend())
{
cout << *iv << " ";
iv++;
}
cout << endl;
}
输出结果如下
使用iterator不可以vector::iterator it = v.begin(); 因为vector是一个模板类需要指定其存储元素的类型。直接写没指定vector具体类型,编译器不知道就会报错(比如可能是vector<double>,vector<int>等)。当然也可以直接用auto自动识别。
3. vector空间增长问题
成员函数 | 接口说明 |
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
resize | 改变vector的元素个数(size) |
reserve | 改变vector的容量(capacity) |
(1). size与capacity
用以下代码验证vector动态增长
#include<iostream>
#include<vector>
//using namespace std;
using namespace std;
int main()
{
vector<int> v;
size_t sz = v.capacity();
cout << "容量为:" << sz << endl;
cout << "元素个数:" << v.size() << endl;
for (int i = 0; i < 100; i++)
{
v.push_back(i);
if (sz != v.capacity())
{
sz = v.capacity();
cout << "当前容量:" << sz << endl;
cout << "当前元素个数:" << v.size() << endl;
}
}
}
输出结果为下图
通过上图我们不难发现,在vs中运行每次增长1.5倍,向上取整
而g++下运行每次增长2倍,并不是所有的vector增容都是增长1.5倍或2倍的。具体增长是多少是看具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
(2). empty与resize与reserve
reserve只负责开辟空间,如果确定要用多少空间,reserve可以缓解vector增容的代价缺陷问题。只影响capacity(),不影响size()
resize在开空间时还会进行初始化,会影响capacity()还会影响size()
如以下代码
#include<iostream>
#include<vector>
//using namespace std;
using namespace std;
int main()
{
vector<int> v1;
size_t sz = v1.capacity();
cout << "v1容量为:" << sz << endl;
cout << "v1元素个数:" << v1.size() << endl;
if(v1.empty())
{
v1.reserve(100);
}
for (int i = 0; i < 100; i++)
{
v1.push_back(i);
if (sz != v1.capacity())
{
sz = v1.capacity();
cout << "v1当前容量:" << sz << endl;
cout << "v1当前元素个数:" << v1.size() << endl;
}
}
vector<int> v2;
cout << "v2容量为:" << v2.capacity() << endl;
cout << "v2元素个数:" << v2.size() << endl;
v2.resize(10);
cout << "v2当前容量为:" << v2.capacity() << endl;
cout << "v2当前元素个数为:" << v2.size() << endl;
for (int i = 0; i < v2.size(); i++)
{
cout << v2[i] << " ";
}
cout << endl;
vector<int> v3;
cout << "v3容量为:" << v3.capacity() << endl;
cout << "v3元素个数:" << v3.size() << endl;
v3.resize(10, 3);
cout << "v3当前容量为:" << v3.capacity() << endl;
cout << "v3当前元素个数为:" << v3.size() << endl;
for (int i = 0; i < v3.size(); i++)
{
cout << v3[i] << " ";
}
cout << endl;
}
输出结果为下图所示
可以验证我们以上说法
4. vector的增删查改
vector的元素操作 | 接口说明 |
push_back | 尾插 |
pop_back | 尾删 |
find | 查找(算法模块实现,不是vector成员接口) |
insert | 在position(指定坐标)之前插入val |
erase | 删除position(指定坐标)位置的数据 |
swap | 交换两个vector的数据空间 |
operator[] | 重载运算符,使其能像数组一样访问 |
(1) . push_back和pop_back
使用代码如下
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(4);
v1.push_back(6);
vector<int>::iterator iv1 = v1.begin();
while (iv1!=v1.end())
{
cout << *iv1 << " ";
iv1++;
}
cout << endl;
v1.pop_back();
iv1 = v1.begin();
while (iv1 != v1.end())
{
cout << *iv1 << " ";
iv1++;
}
cout << endl;
}
输出结果为
(2). find与insert与erase
代码如下
#include<iostream>
#include<vector>
//#include<algorithm>
//using namespace std;
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(4);
v1.push_back(6);
vector<int>::iterator pos1 = find(v1.begin(), v1.end(), 4);
cout << *pos1 << endl;
v1.insert(pos1, 10);
vector<int>::iterator iv = v1.begin();
while (iv != v1.end())
{
cout << *iv << " ";
iv++;
}
cout << endl;
vector<int>::iterator pos2 = find(v1.begin(), v1.end(), 6);
v1.erase(pos2);
iv = v1.begin();
while (iv != v1.end())
{
cout << *iv << " ";
iv++;
}
cout << endl;
}
输出结果为
(3). swap与operator[]
基本使用代码为
#include<iostream>
#include<vector>
//#include<algorithm>
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(4);
v1.push_back(6);
vector<int> v2;
v2.push_back(5);
v2.push_back(8);
v2.push_back(2);
v2.push_back(1);
v2.swap(v1);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
for (size_t i = 0; i < v2.size(); i++)
{
cout << v2[i] << " ";
}
cout << endl;
}
输出结果如下
5. vector迭代器失效问题
迭代器的主要作用就是能让算法不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装。 例如vector的迭代器就是原生态指针T*
迭代器失效实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间会造成程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)
(1). 改变空间
会引起底层空间改变的操作都可能使迭代器失效
比如resize、reserve、insert、assign、push_back等。
#include<iostream>
#include<vector>
//#include<algorithm>
using namespace std;
int main()
{
vector<int> v1{ 1,2,3,4,5,6 };
vector<int>::iterator iv1 = v1.begin();
//将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
v1.resize(100,8);
while (iv1 != v1.end())
{
cout << *iv1 << " ";
iv1++;
}
cout << endl;
vector<int>v2{ 2,5,6,8,9 };
vector<int>::iterator iv2 = v2.begin();
//reserve的作用就是改变扩容大小但不改变有效元素个数
v2.reserve(100);
while (iv2 != v2.end())
{
cout << *iv2 << " ";
iv2++;
}
cout << endl;
vector<int>v3;
vector<int>::iterator iv3 = v3.begin();
//插入元素期间,可能会引起扩容,而导致原空间被释放
v3.insert(v3.begin(), 0);
v3.push_back(1);
while (iv3 != v3.end())
{
cout << *iv3 << " ";
iv3++;
}
cout << endl;
vector<int>v4;
vector<int>::iterator iv4 = v4.begin();
v4.assign(10, 4);
while (iv4 != v4.end())
{
cout << *iv4 << " ";
iv4++;
}
cout << endl;
}
以上所有迭代器全都失效
出错原因如下
以上操作,都有可能导致vector扩容,也就是说vector的旧空间被释放掉,而在打印的时候,iv1,iv2...使用的还是之前的旧空间,对这些迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。
解决方式:在以上影响底层空间的操作完成之后,若想通过迭代器操作vector中的元素,只需给it重新赋值即可。
(2). 删除操作导致的失效
#include<iostream>
#include<vector>
//#include<algorithm>
using namespace std;
int main()
{
vector<int> v1{ 1,2,3,4,5,6 };
vector<int>::iterator pos = find(v1.begin(), v1.end(), 5);
v1.erase(pos);
cout << *pos << endl;
}
erase删除pos位置元素,pos位置之后的元素会往前移,不会导致底层空间改变,理论上迭代器不会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end()的位置,而end()位置是没有元素的,此时pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
(3). Linux下的检测
Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端
1. 扩容后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
2. erase删除任意位置代码后,Linux下迭代器并没有失效,因为空间还是原来的空间,后续元素往前搬移了,旧迭代器位置还是有效的
3. erase删除的迭代器若是最后一个元素,此时旧迭代器是无效的
SGL STL中,迭代器失效后,代码不一定会崩溃,但是运行结果肯定不对,
如果迭代器不再begin()和end()范围内,肯定会崩溃的。
另外
与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
这篇文章到这里就结束啦~喜欢可以点一下赞
(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤