vector【实现】:迭代器失效以及非法的间接寻址、深拷贝中的浅拷贝。

 vector模拟实现_云的小站的博客-CSDN博客


目录

主题:

迭代器失效

Insert导致的迭代器失效

ereas导致的迭代器失效

非法的间接寻址

深拷贝中的浅拷贝。


主题:

1)迭代器失效

2)非法的间接寻址

3)深拷贝中的浅拷贝

迭代器失效

什么是迭代器失效,在vector里我们的迭代器其实就是指针

	templateclass vector{public:typedef Ty val_type;typedef val_type* iterator;//.....

所以在vector的迭代器失效其实是发生了野指针的问题。

失效发生常发生在Insert与ereas对pos的多次访问中。

Insert导致的迭代器失效

代码bug不考虑

 

这是STL库里面的vector的报错


我们自己实现的(9条消息) vector模拟实现_云的小站的博客-CSDN博客


发现第二次使用insert插入数据的时候,无论是库还是自己实现都不被允许,这是为什么呢,干嘛调试观察代码

插入前pos地址在d的有效数据范围内(start~finish)

插入后pos位置未改变,但是d的数据存放的位置改变。所以这个时候在下一次的Insert将失败 

看看库里的流程

 

 pos也成为了野指针,为什么呢?

        在vector扩容都是异地扩容,当Insert后原来的空间被释放,而pos指向的为原来的空间,当第一次Insert内发生了扩容,形参pos改变插入了数据,但是实参pos不被修改。第二次Insert插入时检测出了pos为野指针报错。就算不报错,我们的插入操作也是失效的。扩容导致的迭代器失效。

ereas导致的迭代器失效

那么ereas没有扩容为什么也会迭代器失效呢??有的STL实现在删除操作时,会调用缩容的操作,当缩容后就会导致pos位置失效。但是一般不会做缩容的操作,我们知道就好。

但是ereas的失效主要体现在使用中,

题目:删除数组中的偶数。

乍一看没什么问题但是数据一旦改变!

进程崩溃:

结果错误:

为什么呢?

崩溃原因是,it超出范围。

数组1  2  3  4  

将2删除,然后it++

将4删除  戏剧性的一幕发生了,

                                                                           原本it现在改于end()比较了,但是我们的it

                                                                          必须先++后比较,避开了循环结束条件。 

   这时候【】是end的位置,it完美错过结束判断。导致了it下一次在ereas的非法访问。

		while (it != d.end())//这里的it>end().

 结果错误原因:删除后出现一次跳过。

将删除数据2

++it(未判断移动到当前位置的数据

                                                                               就贸然it++,忽略了it当前的数据是否需要删除)

 结果有误!!!!。

结论:如果最后数据为删除程序崩溃,如果两个偶数连在一起,程序结果有误。

而12345的数据数组,恰好避开了2种错误。

那怎么才能对呢??

接收ereas返回值重新定义it值,it自增需要条件。vector::ereas在库中实现返回删除位置的下一个数据,在vector中其实就是返回pos的位置

 代码改为。

while (it != d.end())
{if (*it % 2 == 0){it = d.ereas(it);}else {++it;}
}

这样我们的结果都可以正确了

 

 结果都是正确的。


对于迭代器失效的问题的根本解决方案就是:不要多次直接使用pos数据!!未改变的pos只能用一次!!

非法的间接寻址

讲一个故事:你手上有一个香蕉,有2只猴子,怎么在不破坏香蕉的情况下,2只猴子都有香蕉吃?

答案是:再去摘一根香蕉......


我们实现构造函数中的一种重载函数:使用N个type初始化对象。

vector(size_type n, const Ty&val= Ty());

但是还有个重载的构造函数

template //可以是其他容器的迭代器
vector(InputIterator begin, InputIterator end)

如果我们这样创建vector对象

vector d1(5, 6);
//报错!!: error C2100: 非法的间接寻址

为什么呢?编译器误调用了vector(InputIterator begin, InputIterator end);

这不是迭代器调用吗?虽然说明是迭代器的构造,但是这是模板函数,int,int也可以调用该函数,导致了,编译器误把对int类型数据解引用,操作错误!!

如何修改呢??我们不可以改变vector(size_type n, const Ty&val= Ty());的数据,但是我们可以重载一个int n,const...的构造函数

vector(size_type n, const Ty&val= Ty());
vector(int n, const Ty&val= Ty());      //重载size_t n,
//vector(long long n, const Ty&val= Ty());//重载size_t n,int n

这样编译器就会调用int n的函数,而不是调用迭代器构造函数。我们不改变size_t n  但是我们重载了int  n 的函数。


深拷贝中的浅拷贝。

深拷贝是深拷贝,浅拷贝是浅拷贝,什么是深拷贝中的浅拷贝???
二维数组的普通拷贝其实就是深拷贝的浅拷贝

三幅图理解!! 

浅拷贝

 这是二维数组的浅拷贝,直接拷贝了src中的地址。


 深拷贝的浅拷贝

我们将二维数组拷贝了一份给des,但是二维数组里面的一维数组地址,我们只是浅拷贝,拷贝了src二维数组中的地址值,而没有根据这些地址值,去拷贝所对应的一维数组。


  深拷贝的深拷贝

 深拷贝二维数组,本且根据原二维数组中的多个一维数组进行深拷贝。

所以我们在实现vector的拷贝逻辑时的reverse与拷贝构造,不可以使用mem*函数进行字节拷贝,而需要自己实现拷贝逻辑

		//1vector(const vector&src){_start = new val_type[src.capacity()];//也可以src.size(),二维数组时的第一层数组开辟空间//memmove(_start, src._start, sizeof(size_type) * src.size());// 自定义类型会极可能报错!!!for (size_t i = 0; i < src.size(); ++i){_start[i] = src._start[i];//如果是自定义成员,会调用他的赋值拷贝,再次进行深拷贝!!!! //而普通内置类型也不会发生错误,完成赋值拷贝}_finish = _start + src.size();_end_of_storage = _start+src.capacity();//和上面同步}

这里的“=”如果左右是自定义类型,就会调用他的赋值重载函数,如果是内置类型,就是编译器的事情了


ps:无论什么样的指针,内置类型指针,自定义类型指针,都属于内置类型!!(都是指针)


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部