C++vector基本功能及模拟

Vector

我们可以把vector简单的理解为顺序表,它的数据是连续的,也可以通过下标去访问,让我们先来了解它的结构。

private:
		iterator _start;//记录开头位置
		iterator _finish;//记录有效数据的结束位置
		iterator _endofstorage;//记录总共开辟多少空间

而它的实现是以模版的方式实现的,为了可以满足各种类型的使用。也因此,它的迭代器类型也有所改变。

template<class T>//模版类型
	class vector
	{
	public:
        //迭代器的类型也随着模版而改变
		typedef T* iterator;
		typedef const T* const_iterator;
        //同样,既然是顺序表,那么它的打印或者遍历就是以区间的方式打印
		void printv(const vector<T>&v)
		{
			typename vector<T> ::const_iterator it = v.begin();
			while (it != v.end())
			{
				cout << *it << "";
				++it;
			}
			cout << endl;
			for (auto e : v)
			{
				cout << e << "";

			}
			cout << endl;
		}
        //迭代器取到头尾,以及const版本
		iterator begin()
		{
			return _start;
		}
		const_iterator begin()const
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator end() const
		{
			return _finish;
		}

而它的构造和析构也很简单,因为是连续的,只要确认头尾即可。

vector()//直接给三个空指针即可
			:_start(nullptr)
			,_finish(nullptr)
			,_endofstorage(nullptr)
		{

		}
~vector()//清空间再置空即可
		{
			delete[] _start;
			_start = _finish = _endofstorage = nullptr;
		}

而它的拷贝构造就有点小坑。

//首先需要考虑空间满了扩容的问题
void reserve(size_t n)
		{
			if (n > getcap())
			{
				size_t sz = getsize();
        //因为memcpy会把地址一起拷贝过来 所以这里反而不能使用memcpy 只能开空间然后传数据
				T* tmp = new T[n];
				if (_start)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				//传完数据再改变一下指向
				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _strat + n;
			}
		}
vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
            //首先先看看要不要扩容
			reserve(v.getcap());
            //然后再直接尾插即可
			for (auto& e : v)
			{
				push_back(e);
			}
		}
//交换
void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
				
		}

vector<T>& operator=(vector<T> v)
		{
			//因为传参会调用拷贝构造,那么我们直接交换,这样可以省事
            //又因为this指针,所以直接给v即可,最后返回*this
			swap(v);
			return *this;
		}

它的基本结构就是这些,那么接下来我们来看看它的基本功能

        //尾插
        void push_back(const T& x)
		{
            assert(pos >= _start);
            assert(pos<= _finish);
            //还是先确认要不要扩容
			if (_finish == _endofstorage)
			{
				
				reserve(getcap() == 0 ? 4 : getcap() * 2);
			}
            //然后直接插入数据然后下标++即可
			*_finish = x;
			++_finish;
		}
        
        //尾删就更简单了 如果它不为空的话直接下标--
		void pop_back(const T& x)
		{
			assert(!empty());
			--_finishi;
		}
        //任意位置插入
		void insert(iterator pos,const T& x)
		{
            //还是老样子先看看要不要扩容
			if (_finish == _endofstorage)
			{
                //为了规避迭代器失效 所以我们的pos得用相对位置
				size_t len = pos - _start;
				reserve(getcap() == 0 ? 4 : getcap() * 2);
				pos = _start + len;
			}
            //然后把pos开始 到finis结束位置的数据都往后移一下 然后插入即可
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finishi;
            //但是你无法保证每次都扩容,所以在插入后迭代器会失效 不要使用它
		}
        //删除
        iterator erase(iterator pos)
		{
			asssert(pos < _finish);
			assert(pos >= _start);
            //先记录我pos位置的下一个
			iterator it = pos + 1;
            //然后从后往前覆盖即可完成删除
			while (it < _finish)
			{
				*(it - 1) = *it;
				++it;
			}
            //最后--有效位置下标即可
			--finish;
            //最后返回pos 此时因为删完了 所以pos是删之前的下一个 把它更新给迭代器就可以避免迭代            
            器失效的问题了
			return pos;
		}

迭代器失效

如果咱认真想想删除的逻辑,我们会发现,如果我们删除或移动完某一个数据之后,之前的下标就不能代表它了,因为数据都有所改变,这个就叫迭代器失效。那么解决它的方法无非就是停止使用改变后的迭代器,用新的,比如erase,它就会返回新的pos,这样规避迭代器失效的问题。

剩下的就是一些收尾了,主要的功能都已经实现了

T& operator[](size_t pos)
		{
            //直接返回下标位置的数据即可
			assert(pos < getsize());
			return _start[pos];
			
		}
		const T& operator[](size_t pos)const
		{
            //再给个const版本即可
			assert(pos < getsize());
			return _start[pos];

		}
        //因为咱的头尾都是指针 所以想要确认有几个数据只能用指针-指针 这个实现起来也是简简单单的
		size_t getcap()
		{
			return _endofstorage - _start;
		}
		size_t getcap()const
		{
			return _endofstorage - _start;
		}
		size_t getsize()
		{
			return _finish - _start;
		}
		size_t getsize()const
		{
			return _finish - _start;
		}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值