c++ vector的模拟实现以及迭代器失效问题

目录

1.vector的模拟实现

2.迭代器失效问题

3.总结


1.vector的模拟实现

这里,我们使用三个指针来控制vector。

 用_start指向头,_finish指向最后一个元素的尾巴,_end指向最大容量。

#include<iostream>
#include<cassert>

using namespace std;

template<class T>
class Vector
{
public:
	typedef T* iterator; //将原生指针模拟成迭代器
	typedef const T* const_iterator; //给一个const版本
	Vector()
		:_start(nullptr)
		, _finish(nullptr)
		, _end(nullptr)
	{}
	Vector(int n, const T& t = T()) 
		:_start(nullptr)
		, _finish(nullptr)
		, _end(nullptr)
	{
		reverse(n); //先开n个空间
		for (int i = 0; i < n; i++)
		{
			push_back(t); //插入这些值
		}
	}
	template<class iterator_begin, class iterator_end>
	Vector(iterator_begin begin, iterator_end end) //迭代器初始化版
		:_start(nullptr)
		, _finish(nullptr)
		, _end(nullptr)
	{
		while (begin != end)
		{
			push_back(*begin);
			begin++;
		}
	}
	void swap(Vector<T>& v)
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_end, v._end);
	}
	Vector(Vector<T>& v) //现代写法
		:_start(nullptr)
		, _finish(nullptr)
		, _end(nullptr)
	{
		Vector<T> temp(v.begin(), v.end()); //先构造一个传入的拷贝
		swap(temp); //再交换
	}

	Vector<T>& operator=(Vector<T> t) //现代写法
	{
		swap(t); //因为t是传值,会发生拷贝。
		return *this;
	}
	iterator begin()
	{
		return _start;
	}
	iterator end()
	{
		return _finish;
	}
	const_iterator begin() const
	{
		return _start;
	}

	const_iterator end() const
	{
		return _finish;
	}
	~Vector() //析构函数
	{
		delete[] _start;
		_start = _finish = _end;
	}
	size_t capacity()
	{
		return _end - _start;
	}
	size_t size()
	{
		return _finish - _start;
	}
	T& operator[](size_t pos)
	{
		assert(pos < size());
		return _start[pos];
	}
	void reverse(size_t n)
	{
		if (n > capacity())
		{
			int sz = size();
			T* temp = new T[n];
			if (_start) //保证非空
			{
				for (int i = 0; i < sz; i++)
				{
					temp[i] = _start[i];
				}
				delete _start;
			}
			_start = temp;
			_finish = _start + sz;
			_end = _start + n;
		}
	}
	void resize(size_t n, const T& val)
	{
		if(n > capacity())
		reverse(n);
		if (n > size())
		{
			while (_finish < _start + n)
			{
				*_finish = val;
				++_finish;
			}
		}
		else
		{
			_finish = _start + n;
		}
	}
	void pop_back()
	{
		assert(_finish > _start);
		--_finish;
	}
	iterator insert(iterator pos, const T& val)
	{
		assert(pos >= _start);
		assert(pos <= _finish);
		if (_finish == _end) //满了
		{
			int len = pos - _start; //标记长度,不然下面找不到了。
			reverse(capacity() == 0 ? 4 : capacity() * 2);//非0开出2倍的空间
			pos = _start + len;	
		}
		iterator cur = _finish-1; //因为finish会指向最后一个元素的尾部
		while (cur >= pos) //从最后一个位置向后移动
		{
			*(cur + 1) = *cur;
			--cur;
		}
		++_finish;
		*pos = val;	
		return pos;
	}
	void push_back(const T& t)
	{
		iterator temp = insert(end(), t); //复用插入
	}
	iterator erase(iterator pos) //返回删除位置下一个的迭代器
	{
		assert(pos >= _start);
		assert(pos <= _finish);

		iterator cur = pos + 1;
		while (cur < _finish)
		{
			*(cur - 1) = *cur; //挪动数据
			++cur;
		}
		--_finish;
		return pos;
	}
	T& front()
	{
		assert(size() > 0);

		return *_start;
	}

	T& back()
	{
		assert(size() > 0);

		return *(_finish - 1);
	}

private:
	iterator _start;
	iterator _finish;
	iterator _end;
};

需要注意的是:我们一般在拷贝构造或者扩容时会采用现代(托管+交换)的写法。

reverse:会新开一个大小n的空间,再将原来的的值拿过来。

拷贝构造:直接调用构造函数构造一个和传入的对象一样的实例,最后和this交换。

与传统的原地处理不同的是,这种方式会创造一个临时变量来托管处理,最后再交换。


2.迭代器失效问题

对于vector迭代器的失效主要分为两种情况:

a.扩容导致的野指针

b.因为挪动数据导致迭代器失效

 以删除元素为例,删除2以后,pos就指向了3。pos指向内容发生了突然变化,这时也就发生了迭代器的失效,pos失去了作用。


3.总结

vector可以通过三个指针实现一个基本版。

要特别注意迭代器失效问题,这是和野指针问题一样的严重程序设计问题。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不会敲代码的运气选手^

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

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

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

打赏作者

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

抵扣说明:

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

余额充值