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

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


目录

主题:

迭代器失效

Insert导致的迭代器失效

ereas导致的迭代器失效

非法的间接寻址

深拷贝中的浅拷贝。


主题:

1)迭代器失效

2)非法的间接寻址

3)深拷贝中的浅拷贝

迭代器失效

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

	template<class Ty>
	class 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 <class InputIterator>//可以是其他容器的迭代器
vector(InputIterator begin, InputIterator end)

如果我们这样创建vector对象

vector<int> 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*函数进行字节拷贝,而需要自己实现拷贝逻辑

		//1
		vector(const vector<val_type>&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:无论什么样的指针,内置类型指针,自定义类型指针,都属于内置类型!!(都是指针)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云的小站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值