5. 数据访问
与string类似,在数据访问中也有很多接口,但是最常用的还是[]的重载,其余基本不常用,这里我们就不过多赘述
[]实际上是一个运算符重载,使vector也具有类似下标访问的能力,返回值是vector中存放元素类型的引用
对于[]的重载,在库里面支持了两种重载,分别是普通类型的和const类型的用于支持多样化的使用环境
怎么判断需要实现const或者非const版本?
- 对于只读接口,只实现const版本即可
- 对于只写接口,只实现非const版本即可
- 对于可读可写的接口,需要同时实现const版本和非const版本
void Test_Access() { vector<int> v(10); for (size_t i = 0; i < v.size(); ++i) { v[i] = i; } for (size_t i = 0; i < v.size(); ++i) { cout << v[i] << " "; } cout << endl; }
6. 数据修改
1. 尾插尾删
1. push_back
尾插数据,插入前会进行扩容操作,每次扩容的大小取决于编译器的实现
2. pop_back
如果vector中有数据的话,尾删一个数据,否则会由assert中断程序或者抛出异常,具体情况取决于编译器的实现
void Test_Modifity() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.pop_back(); v.pop_back(); v.pop_back(); v.pop_back(); v.pop_back(); v.pop_back(); }
2.任意位置的插入删除
1. insert
在传入的任意位置插入一个数据或者迭代器区间的数据
2. erase
删除任意位置的值或者任意一个迭代器区间的值
void Test_Modifity2() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.insert(v.begin() + 3, 30); v.erase(v.begin()); for (auto e : v) { cout << e << " "; } cout << endl; }
这里注意一下,vector中会出现迭代器失效的问题
❗❗==vector中的迭代器失效问题==❗❗
❓第一个问题:迭代器的出现原因是什么?
✅迭代器的设计模式,为了不暴露底层实现细节,提供统一的方式来访问容器,对于vector,其迭代器本质上就是原生指针T*,所以对vector来说,迭代器失效的原因就是原迭代器指向的空间被销毁,导致出现野指针。
❓第二个问题:导致迭代器失效的操作有哪些?
✅迭代器失效的原理是底层空间改变,导致产生野指针,所以所有的底层空间的改变都有可能使迭代器失效,例如:reserve,resize,push_back,insert等。
✅除了对底层空间的改变之外,erase也会导致迭代器失效。
❓第三个问题:按照我们上一个问题的逻辑,erase没有使底层空间发生改变啊,为什么也会使迭代器失效?
✅虽然erase没有改变底层空间,但是,如果erase删除的是vector中最后一个元素,刚好删除完之后pos位置是end指向的位置,那么迭代器就失效了。
✅就算删除的不是最后一个元素,那么迭代器指向的位置的值也是改变了的,严格意义上来说,也是不能实现我们所需要的功能的,所以也可以认为是迭代器失效了。
❓第四个问题:只有vector会遇到迭代器失效的的情况吗,string有没有迭代器失效的情况?
✅不只是vector有,string和其他的容器都有迭代器失效的情况。
❓第五个问题:迭代器失效的问题怎么解决呢?
✅在上文中,我们讲解了vector的主要接口,可以注意到,能够引起迭代器失效的接口函数的返回值都是迭代器,这里返回的迭代器就是我们所需要的有效的迭代器。所以,在使用前对迭代器进行重新赋值即可解决。
//关于迭代器失效解决的例题: //对于使用vector存储的数组{0,1,2,3,4,5,6,7,8,9},删除其中所有的偶数元素 int main() { vector<int> v(10); for (size_t i = 0; i < 10; ++i) { v[i] = i; } vector<int>::iterator it = v.begin(); while (it != v.end()) { if (*it % 2 == 0) { it = v.erase(it); } else { ++it; } } for (auto e : v) { cout << e << " "; } cout << endl; return 0; }
7.其他接口
1. clear
删除vector内部所有数据(本质上做的操作就是将vector的size置为0)
2. swap
vector内部实现的一个交换函数,提升效率。