C++初阶vector(中)

Posted Huang_ZhenSheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++初阶vector(中)相关的知识,希望对你有一定的参考价值。

目录

vector模拟实现

reserve 

resize 

迭代器失效

insert

模拟实现insert: 

erase

模拟实现erase: 

总结 


vector模拟实现

具体的模拟实现代码详见【C++初阶】vector(下)

reserve 

//开空间
		void reserve(size_t n)
		
			if (n > capacity())
			
				//动态申请n个T类型的空间
				T*tmp = new T[n];
				//从_start位置开始向后复制sizeof(T)*size()字节的数据到tmp的内存位置
				memcpy(tmp, _start, sizeof(T)*size());
				_start = tmp;
				_finish = _start + size();
				_endofstorage = _start + n;
			
		

运行上面的代码,会发现挂了——why?

size()算原来旧空间的数据,旧空间的话——_finish和_start都是0,零减零应该还是0

 调试显示_finish是0,而_start是已经指向新空间了,所以相减为负了

改造:把size()提前存好

//开空间
		void reserve(size_t n)
		
			if (n > capacity())
			
				size_t sz = size();
				//动态申请n个T类型的空间
				T*tmp = new T[n];
				//从_start位置开始向后复制sizeof(T)*size()字节的数据到tmp的内存位置
				memcpy(tmp, _start, sizeof(T)*size());
				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			
		

resize 

//开空间+初始化
		void resize(size_t n, const T& val = T())
		
			if (n <= size())
			
				_finish = _start + n;
			
			else//n>size()
			
				//空间容量不够
				if (n > capacity())
				
					reserve(n);
				
				//size()<n<capacity()
				while (_finish < _start + n)//指针
				
					*_finish = val;
					_finish++;
				
			
		

迭代器失效

insert

namespace std

	void test_vector1()
	
		vector<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		vector<int>::iterator pos = find(v.begin(), v.end(), 2);
		if (pos != v.end())
		
			v.insert(pos, 20);//2的前面插入20
		
		//在insert以后pos就失效了
		cout << *pos << endl;//访问
		*pos = 100;//修改
	

调试出现报错:

在insert以后pos就失效了——增容导致的(扩容之后pos还指向旧空间) 

反观下面这段代码,先增容后,没有报错:

namespace std

	void test_vector1()
	
		std::vector<int>v;

		v.reserve(8);//先增容

		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		std::vector<int>::iterator pos = find(v.begin(), v.end(), 2);
		if (pos != v.end())
		
			v.insert(pos, 20);//2的前面插入20
		
		cout << *pos << endl;//访问
		*pos = 100;//修改
		pos++;
	

在insert过程空间足够,没有增容,pos还是指向原来的位置

访问不会报错,那么我们依旧认为pos失效了

这里的失效指的是pos的意义变了,pos不再指向原来的值!

总结insert的失效2中情况:

第一种:由于insert扩容,导致pos失效,pos指向的空间释放,pos本质上是一个野指针

第二种:insert插入数据,没有扩容,我们也认为pos失效了,因为pos的意义变了,不再指向原来的数据

正确的写法:返回新插入元素的位置

if (pos != v.end())

	pos = v.insert(pos, 20);

模拟实现insert: 

下面模拟实现一下insert:

下面注意reserve之后里面的_start会更新,隐藏着迭代器失效的问题!

iterator/*返回值*/ insert(iterator pos, const T& x)
		
			//判断pos的位置是不是合法的
			assert(pos >= _start && pos <= _finish);
			//记录一下pos的相对位置
			size_t len = pos - _start;
			//开空间
			if (_finish == _endofstorage)
			
				//万一为空的时候为0,所以按下面的方式进行
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;

				//reserve之后里面的_start会更新
				reserve(newcapacity);
				//更新一下pos的位置
				pos = _start + len;
			
			//挪动数据
			iterator end = _finish - 1;
			while (end >= pos)
			
				*(end + 1) = *end;
				end--;
			
			//插入数据
			*pos = x;
			_finish++;
			return pos;
		

erase

namespace std

	void test_vector2()
	
		std::vector<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		std::vector<int>::iterator pos = find(v.begin(), v.end(), 2);
		if (pos != v.end())
		
			v.erase(pos);
		
		cout << *pos << endl;
		*pos = 100;
	

调试出现报错: 不能解引用!

erase导致pos失效了,pos没有野指针,只是意义变了,但是vs版本下进行了强制检查,都不能访问

下面这段代码同样会报错:

namespace std

	void test_vector2()
	
		std::vector<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//要求删除v中所有偶数
		std::vector<int>::iterator it = v.begin();
		while (it != v.end())
		
			if (*it % 2 == 0)
			
				v.erase(it);
			
			it++;
		
	

 正确的写法:erase返回删除数据的下一个数据的位置

namespace std

	void test_vector2()
	
		std::vector<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//要求删除v中所有偶数
		std::vector<int>::iterator it = v.begin();
		while (it != v.end())
		
			if (*it % 2 == 0)
			
				//erase返回删除数据的下一个数据的位置
				it = v.erase(it);
			
			else
			
				it++;
			
		
		for (auto e : v)
		
			cout << e << " ";
		
		cout << endl;
	

模拟实现erase: 

下面模拟实现一下insert:

iterator erase(iterator pos)
	
		assert(pos >= _start && pos < _finish);
		iterator it = pos + 1;
		while (it != _finish)
		
			*(it - 1) = *it;
			it++;
		
		_finish--;
		return pos;
	

总结 

总结:insert和erase以后的迭代器都失效了,一定不要直接去访问或解引用insert或erase后的迭代器

以上是关于C++初阶vector(中)的主要内容,如果未能解决你的问题,请参考以下文章

C++初阶vector(中)

C++ 初阶vecotr底层框架模拟实现

C++ 初阶vecotr底层框架模拟实现

C++初阶第十篇——vector(vector常见接口的用法与介绍+vector的模拟实现)

C++初阶---vector的使用及模拟实现 (待写。。)。

C++初阶vector(上)