文章目录
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6896cd394703fd690e226525465afb0b.png)
使用这种方式定义vector和我们在顺序表中定义有何区别?
本质上是一样的。只不过这种利用了指针-指针的性质。start是左闭,finish,end of storage是右开的
vector成员变量的start,finish,end of storage和我们以前顺序表结构体的size,capacity,int* arr相比有什么优点呢?
我们在string模拟insert时,pos==0时因为无符号 - -仍然是无符号导致循环停不下来。
这里指针start不会是0号地址,0号地址是无效地址,所以while(pos>=start)条件会停下来,这是start.finsih,eof带给我们的优势。
著名问题:迭代器失效
问题引入
情况一,vector无数据,push_back复用insert,代码崩了
情况二,即使push_back不复用insert,在insert时如果发生扩容,就会产生问题插入一个随机值
解决内部迭代器失效
原先的pos指向旧空间,如果发生扩容开辟了新空间,我们就要找到新空间中pos相对的位置,不然就会发生迭代器失效问题,程序会崩溃或者随机值,并且这种情况是偶发性的错误(如果不扩容那没什么问题)
外部迭代器p失效
insert以后迭代器可能会失效(失效的原因还是扩容,p不指向原来的空间并且虽然内部迭代器更新了但更新的是形参改变不了实参!),如果不扩容就是正常的。
为了解决形参pos的改变不会修改实参p,我们试图加上&,但是这会导致begin()函数调用和表达式返回临时变量具有常性,造成权限放大,又试图加上const,但这样函数体内pos还要更新,更是不可能加上const
所以,insert以后就不要使用这个迭代器p了,因为它可能失效了
那怎么办呢?
库里面Insert带了一个返回值,返回新插入元素的位置的迭代器!
如果你想继续访问P那么就去接收返回值。
erase后迭代器失效
本来1 2 3 4 5
现在要删头,删除后我还要访问it和++it,此时原来指向1的it,现在指向2,就是说it不指向原来的元素了,此时认定erase后迭代器也会失效
上面是我们模拟实现的,在stl标准库中,对这种erase后继续访问it迭代器的行为直接进行了崩溃处理
linux中头删或者尾删貌似没什么问题
但是有些情况下linux的这种不直接报错,反而更加恶心
删除所有的偶数
情景1
1 2 3 4 5
删除后1 3 5
it指向2,删除2,迭代器失效指向3,后++it指向了4,再删除4,迭代器失效指向5,后++it循环结束
这只是偶然删除掉了
情景2
1 2 2 3 4 5
基于上面的情景多出来的偶数就被++跳过了
情景3
1 2 2 3 4 5 6
end()返回finsih
finish–,it++他们继续判断it != v.end()就一直停不下来了,发生了段错误越界
我们可能会想到以下代码来解决场景3
虽然再Linux里可以跑,但是vs中直接崩溃,它认为erase后it迭代器失效了
所以stl里的erase和insert一样接受返回值,返回删除后指向的下一个位置
总结
insert 和 erase的迭代器it使用后认为it都失效
insert可能扩容失效或者不扩容不失效,但你再不同平台下什么时候扩容你是不清楚的,所以都认为insert后迭代器失效!
要想继续使用,需要利用insert 和 erase的返回值
隐藏的浅拷贝问题
reserve中对于Vector 如果用memcpy按字节拷贝会让新空间的string对象指向旧空间,并且旧空间会被释放,新空间就指向被释放的空间,在析构的时候他们就会析构2次。
解决
可以一个一个对象的拷贝,如果是自定义类型利用赋值重载实现深拷贝,内置类型还是浅拷贝就可以!
不仅仅是reserve中,拷贝构造中同样需要一个一个拷贝,不然会发生同样析构2次问题
vector中指针关系
关于指针 关系判断 < <= 还是 !=
比如链表就没法用< <=
构造函数模板调用问题
调用n个val的构造反而会调用迭代器区间构造,出现非法的间接寻址问题
非法的间接寻址 目前 指针 迭代器 可解引用 其他不行
说人话就是把10当作迭代器区间*first解引用了,就报错了
原因
默认识别类型
模板匹配规则
能有现成的就吃现成的(原生函数),没有现成的就吃最喜欢的(模板)
解决
库里面多定义了函数重载,让int类型有现成的可吃,就不会匹配到迭代器区间函数了