1. vector介绍及使用
1.1 vector介绍
- vector(向量)是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。
- vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,增加和压缩数据,一个容器中的所有对象都必须是同一种类型的。简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据
- vector是一个类模板(class template)。使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型
1.2 vector使用
1)vector常见构造
| 函数名称 | 接口说明 |
|---|---|
| vector()(重点) | 无参构造 |
| vector(size_type n, const value_type& val = value_type()) | 构造并初始化n个val |
| vector (const vector& x) (重点) | 拷贝构造 |
| vector (InputIterator first, InputIterator last) | 使用迭代器进行初始化构造 |
| vector (initializer_list<value_type> il) | 使用initializer_list类型,这种类型的对象由编译器从初始化列表声明中自动构造,初始化列表声明是用大括号括起来的逗号分隔元素列表 |
vector<int> v1;
vector<int> v2(4, 100);
vector<int> v3(v2.begin(), v2.end());
vector<int> v4(v3);
vector<int> v5({1,2,3,4,5});
vector<int> v6={1,2,3};
2)iterator 的使用
| 接口说明 | |
|---|---|
| begin+end | 获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下 一个位置的iterator/const_iterator |
| rbegin+rend | 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置 的reverse_iterator |

3) 空间容量
| 函数 | 接口说明 |
|---|---|
| size | 数据个数 |
| capacity | 空间容量大小 |
| empty | 判空 |
| resize(重点) | 改变size大小,再初始化 |
| reserve(重点) | 改变capacity大小 |
- capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是 根据具体的需求定义的
- resize在开空间的同时还会进行初始化,影响size
4)增删查改
| 函数 | 接口说明 |
|---|---|
| push_back(重点) | 尾插 |
| pop_back (重点) | 尾删 |
| find | 查找。(注意这个是算法模块实现,不是vector的成员接口) |
| insert | 在pos位之前插入val |
| erase | 删除pos位的数据 |
| swap | 交换两个vector的数据空间 |
| operator[] (重点) | 像数组一样访问 |
1.3 vector 迭代器失效问题(重点)
vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
迭代器失效解决办法:在使用前,对迭代器重新赋值即可
1) 扩容引起的野指针问题
会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、 assign、push_back等

解决方法:给 i 重新赋值即可
2)删除指定位置数据
v.erase(pos);
cout << *pos << endl; // 此处会导致非法访问
erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end 的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了
但下方代码运行成功,因为避免了数据位置问题
//删除所有偶数
auto i = v1.begin();
while (i != v1.end())
{
if (*(i) % 2 == 0)
v1.erase(i);
else
i++;
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
3)注意
Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
2.vector模拟实现
2.1 实现
2.2 使用memcpy拷贝问题
- memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存 空间中
- 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错
- 如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时就会出错,因为memcpy的拷贝实际是浅拷贝
上方代码实现reserve扩容时没有用memcpy浅拷贝,而是使用赋值重载深拷贝,使指向新地址


被折叠的 条评论
为什么被折叠?



