STL中vector的使用及其模拟实现

目录

1.vector对象的构造方式:

2.vector对象的三种遍历方式:

3.和容量相关联的使用:

1.有效元素的获取和空间大小的获取。

2.resize:将顺序表有效元素个数增加。

3.reserve:扩容

4.获取元素:

1.front和back

2.'[]'运算符重载

5.操作元素:

1.push_back和pop_back

2.insert:

3.clear()清空元素

4.erase删除某个位置的元素或者某个区间元素

5.交换两个对象

6.vector迭代器失效:

1.什么是迭代器?

2.为什么会迭代器失效?

3.那么那些操作会导致迭代器失效呢?

4.怎样避免迭代器失效:

7.vector的模拟实现


1.vector对象的构造方式:

  • STL中vector的使用及其模拟实现_第1张图片

2.vector对象的三种遍历方式:

  • STL中vector的使用及其模拟实现_第2张图片

3.和容量相关联的使用:

1.有效元素的获取和空间大小的获取。

  • STL中vector的使用及其模拟实现_第3张图片

2.resize:将顺序表有效元素个数增加。

  • STL中vector的使用及其模拟实现_第4张图片

resize的使用:

我们知道它在增大有效元素个数时如果空间不够会扩容我们测试一下他是如何扩容的

  • STL中vector的使用及其模拟实现_第5张图片

运行结果

  • STL中vector的使用及其模拟实现_第6张图片

可以得出结论,在扩容时是按照1.5倍扩容的(在vs平台下,在g++下是按照2倍),但是当减少有效字符个数时并不会减少容量。

3.reserve:扩容

使用:只是单纯的将容量增大了,并没有填充其他内容

  • STL中vector的使用及其模拟实现_第7张图片

我们来测试一下它的扩容规律(在vs平台下):

  • STL中vector的使用及其模拟实现_第8张图片

运行结构:

  • STL中vector的使用及其模拟实现_第9张图片

我们可以得出结论就是在传入新的容量大于原来容量时,会按照传入容量的大小来扩容(我猜测是因为实现者考虑到如果是有些使用者用比较大的自定义类型来填充顺序表时如果开辟的空间过多会造成浪费所以按需开辟)。

4.获取元素:

1.front和back

  • STL中vector的使用及其模拟实现_第10张图片

2.'[]'运算符重载

  • STL中vector的使用及其模拟实现_第11张图片

5.操作元素:

1.push_back和pop_back

  • STL中vector的使用及其模拟实现_第12张图片

2.insert:

  • STL中vector的使用及其模拟实现_第13张图片

运行结果:

  • STL中vector的使用及其模拟实现_第14张图片

3.clear()清空元素

  • STL中vector的使用及其模拟实现_第15张图片

4.erase删除某个位置的元素或者某个区间元素

  • STL中vector的使用及其模拟实现_第16张图片

运行结果:

  • STL中vector的使用及其模拟实现_第17张图片

5.交换两个对象

  • STL中vector的使用及其模拟实现_第18张图片

运行结果:

  • STL中vector的使用及其模拟实现_第19张图片

6.vector迭代器失效:

1.什么是迭代器?

迭代器就是类似于指针的东西,对它操作就和对指针一样的操作方式。

2.为什么会迭代器失效?

我们先来看迭代器失效的一个场景

  • STL中vector的使用及其模拟实现_第20张图片

  • STL中vector的使用及其模拟实现_第21张图片

  • STL中vector的使用及其模拟实现_第22张图片

我们可以看到在一开始我们将迭代器创建出来,然后插入元素,当容器扩容后对迭代器进行解引用访问就报错了,这是因为,在进行扩容时,底层直接就将原来旧的空间释放掉,然后将内容拷贝到新开辟的空间中,将原来的指针指向新的空间,而这样迭代器的那片空间就被释放掉了,所以扩容之后再对迭代器进行操作,就有可能会导致迭代器失效问题。

3.那么那些操作会导致迭代器失效呢?

首先导致迭代器失效的原因就是容器扩容到导致迭代器指向的旧空间的释放然后导致迭代器失效。所以一切有可能导致扩容的操作都有可能导致迭代器失效如:

push_back()

  • STL中vector的使用及其模拟实现_第23张图片

clear()

  • STL中vector的使用及其模拟实现_第24张图片

按理说只有当容器扩容时地址改变才会产生迭代器失效的错误,这里是为什么呢?我们再去g++编译器试一下看一下会不会报错

  • STL中vector的使用及其模拟实现_第25张图片

运行结果我们发现并没有报错正常运行,所以使用clear清空元素,然后出现迭代器失效的情况应该是在vs平台下检测严格才会报错。

  • STL中vector的使用及其模拟实现_第26张图片

insert()

  • STL中vector的使用及其模拟实现_第27张图片

erase()

  • STL中vector的使用及其模拟实现_第28张图片

同理我们来测试一下删除首元素在g++平台下会不会导致迭代器失效

  • STL中vector的使用及其模拟实现_第29张图片

运行结果:我们发现也并没有报错,那我们就可以得出一个结论在vs平台下只要首元素被删除那么就会产生迭代器失效的错误。

  • STL中vector的使用及其模拟实现_第30张图片

这里要注意删除其他位置元素是不会导致迭代器失效的

  • STL中vector的使用及其模拟实现_第31张图片

reverse()

  • STL中vector的使用及其模拟实现_第32张图片

resize()

  • STL中vector的使用及其模拟实现_第33张图片

operator=

  • STL中vector的使用及其模拟实现_第34张图片

assign()

  • STL中vector的使用及其模拟实现_第35张图片

swap()

  • STL中vector的使用及其模拟实现_第36张图片

4.怎样避免迭代器失效:

1.在使用erase时由于erase删除当前迭代器的位置,他就会返回下一个迭代器的位置,所以我们只需要每次将迭代器位置删除后更新即可。

  • STL中vector的使用及其模拟实现_第37张图片

  • STL中vector的使用及其模拟实现_第38张图片

7.vector的模拟实现

#include
#include
#include
using namespace std;
namespace wbx
{
	template
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		/构造和析构
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, end_of_storage(nullptr)
		{}
		vector(size_t n, const T &val = T())//构造n个T类型的val值
			:_start(nullptr)//指针要初始化这是一个良好的编程习惯
			,_finish(nullptr)
			,end_of_storage(nullptr)
		{
			_start = new T[n*sizeof(T)];
			_finish = _start+n;
			end_of_storage = _finish;
			for (size_t i = 0; i < n; i++)
			{
				_start[i] = val;
			}
		}
		vector(int n,const T &val = T())//构造n个T类型的val值,这里的val必须要用const修饰不然当传入参数时是编译通过不了的
			:_start(nullptr)//指针要初始化这是一个良好的编程习惯
			, _finish(nullptr)
			, end_of_storage(nullptr)
		{
			_start = new T[n*sizeof(T)];
			_finish = _start + n;
			end_of_storage = _finish;
			for (int i = 0; i < n; i++)
			{
				_start[i] = val;
			}
		}
		vector(const vector &v)//拷贝构造
			:_start(nullptr),
			_finish(nullptr),
			end_of_storage(nullptr)
		{
			//vector temp(v.begin(), v.end());//这里不可以调用普通类型的返回迭代器的指针,
			vector temp(v.cbegin(), v.cend());//因为const对象只能调用const类型的成员函数
			this->swap(temp);
		}

		template//这里要再定义一个迭代器类的模板,因为这里假设我们vector中存放的不同类型对象
								//所返回的迭代器类型也是不同的,所以我们这里重新设置一个模板类对于多种不同
								//类型具有普遍的适用性
		vector(Iterator first, Iterator last)
		{
			size_t n = last - first; //这里获取frist和last之间的距离应当写一个distance函数来
										//获取他们之间的距离,这里这样写是因为简单模拟实现
			_start = new T[n];
			_finish = _start;
			end_of_storage = _start + n;
			while (first != last)
			{
				*_finish = *first;
				_finish++;
				first++;
			}
		}
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = nullptr;
				_finish = nullptr;
				end_of_storage = nullptr;
			}
		}
		运算符重载:
		vector operator=(vector v)
		{
			this->swap(v);
			return *this;
		}
		
		T& operator[](size_t index)
		{
			if (index < 0 || index >= size())
			{
				assert(false);
			}
			return *(_start + index) ;
		}
		///容量相关
		size_t size()
		{
			int a = 0;
			return a=_finish - _start;
		}
		size_t capacity()
		{
			return end_of_storage - _start;
		}
		bool empty()
		{
			if (_start == _finish)
			{
				return true;
			}
			return false;
		}
		void resize(size_t n, T val = T())
		{
			size_t oldsize = size();
			if (n >capacity())
			{
				reserve(n - capacity());
			}
			for (int i = oldsize; i < n; i++)
			{
				_start[i] = val;
			}
			_finish = _start + n;//如果新的size小于老的size这里直接访问不到了
		}
		void reserve(size_t n)
		{
			T *temp = new T[n];
			for (int i = 0; i < size(); i++)
			{
				temp[i] = _start[i];//这里必须要用=来进行拷贝如果用其他如memcpy的话就会发生浅拷贝的情况
			}
			size_t oldsize = size();
			if (_start)
			{
				delete[] _start;
			}
			_start = temp;
			_finish = _start + oldsize;
			end_of_storage = _start + n;
		}
		迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator cbegin()const
		{
			return _start;
		}
		const_iterator cend()const
		{
			return _finish;
		}
		/插入函数
		void push_back(T val)
		{
			if (_finish == end_of_storage)
			{
				reserve(2 * capacity());
			}
			*_finish = val;
			_finish++;
		}
		void pop_back()
		{
			if (empty())
			{
				assert(false);
			}
			_finish--;
		}
		iterator insert(iterator pos,T val)
		{
			if (empty()||pos==_finish)
			{
				push_back(val);
				return pos;
			}
			if (_finish == end_of_storage)
			{
				reserve(capacity() + 1);
			}
			iterator temp = _finish-1;
			while (temp >= pos)
			{
				*(temp + 1) = *temp;
				temp--;
			}
			*pos = val;
			_finish++;
			return pos;
		}
		iterator erase(iterator pos)
		{
			if (pos < _start || pos >= _finish)
			{
				assert(false);
			}
			iterator ret = pos;
			while (pos != _finish - 1)
			{
				*pos = *(pos + 1);
				pos++;
			}
			_finish--;
			return ret + 1;
		}
		T & front()
		{
			return *(_start);
		}
		T &back()
		{
			return *(_finish-1);
		}
		交换函数
		void swap(vector  &v)
		{
			std::swap(v._start, _start);
			std:: swap(v._finish, _finish);
			std::swap(v.end_of_storage, end_of_storage);
		}
	private:
		iterator _start;
		iterator _finish;
		iterator end_of_storage;
	};
}
using namespace std;
wbx::vector static v4(5, 4);
void test1()
{
	wbx::vector v1(5, 1);
	wbx::vector v2(5, 2);
	wbx::vector v3(v2);
	v1.reserve(10);
	v1[3] = 0;
	v2 = v1;
	v2[1] = 0;
	//static wbx::vector v3(5, 3);
	v1.resize(10, 9);
	v1.pop_back();
	v1.push_back(11);
	v1.push_back(11);
	v1.insert(v1.begin() + 1, 100);
	v1.erase(v1.begin() + 3);
	v1.erase(v1.begin() + 3);
	v1.back()++;
}

int main()
{
	//test1();
	return 0;
}

你可能感兴趣的:(C++,c++)