Stl中vector解析&简单模拟

目录

前言

vector功能概览

vector基本结构

vector函数模拟

迭代器模拟

begin()

end()

容量相关函数

size()

capacity()

reserve()

resize()

增删查改

insert()

erase()

push_back()

pop_back()

迭代器失效问题

 []访问操作符

构造函数

无参构造

迭代器区间构造

vector(const size_t n, const T& val = T())

拷贝构造函数

析构函数

swap()

= 重载

小结

前言

vector也是Stl中比较重要的一种容器,相比较于string,vector所存储的数据类型更多,不再仅仅局限于char类型的数据。

vector功能概览

 考虑到内容要精简一点,我们挑选其中比较有代表性的功能函数来讲解。

vector基本结构

 上面我们提到vector可以存放多种数据,因此我们在模拟实现的时候优先考虑模板类,成员变量直接用模板类型。

template<class T>
	class vector
	{
	public:
		typedef T* iterator;//迭代器类型
		typedef const T* const_iterator;
    private:
		iterator _start;//数据开始的地方
		iterator _finish;//最后一个数据的下一位
		iterator _endofstoage;//空间中最后位置的下一位
	};

vector函数模拟

迭代器模拟

begin()

返回值:数据的起始位置

这里直接考虑返回指针变量_start

iterator begin()
{
	return _start;
}

//const成员变量调用的迭代器
const_iterator begin() const
{
	return _start;
}

end()

返回值:数据末尾的下一位置

这里直接考虑返回指针变量_finish

iterator end()
{
	return _finish;
}

//const成员变量调用的迭代器
const_iterator end() const
{
	return _finish;
}

容量相关函数

size()

返回值:数据的有效个数

size_t size() const
{
	return _finish - _start;//指针相减即可
}

capacity()

返回值:空间能够存放的数据个数

size_t capacity() const
{
	return _endofstoage - _start;
}

reserve()

功能:扩容,开辟新的空间来存放数据

void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t gap = size();//避免开辟空间后找不到原先的数据个数
		T* tmp = new T[n];
		if (_start)//将旧空间的数据挪动到新空间去
		{
			for (size_t i = 0; i < size(); ++i)
			{
				tmp[i] = _start[i]; //不使用memcpy函数是避免浅拷贝的情况出现,'='下面会重载
                                    //例:vector<vector<int>>的拷贝
			}
		}
		delete[] _start;      //释放旧空间
		_start = tmp;           //重新更新各个指针的位置
		_finish = _start + gap;   
		_endofstoage = _start + n;
	}
}

resize()

功能:改变数据的个数,空间不够的话进行扩容。

void resize(size_t n, const T& val =T())  //缺省传值,T()为该类型数据的构造函数
{
	if (n > capacity())
	{
		reserve(n);  //空间不够扩容
	}
	for (size_t i = size(); i < n; ++i)  //如果大于原来的数据个数就会把后面的数据赋值
	{
		_start[i] = val;
	}
	_finish = _start + n;   //更新数据的结尾位置
}

增删查改

insert()

功能:在对应的位置插入数据

图解:

 代码实现: 

iterator insert(iterator pos, const T& x)
{
	assert(pos >= _start && pos <= _finish);
	if (_endofstoage == _finish)
	{
		size_t gap = pos - _start;      //防止扩容之后迭代器失效,这个知识点下面会讲解
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
		pos = _start + gap;
	}
	iterator end = _finish - 1; //挪动数据
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;   //插入数据
	++_finish;   //更新数据结尾位置
	return pos + 1; //同样是防止迭代器失效
}

erase()

功能:在对应的位置删除数据

图解:

代码实现: 

iterator erase(iterator pos)
{
	assert(pos >= _start && pos <= _finish);
	iterator tmp = pos;
	while (tmp < _finish) //删除并挪动数据
	{
		*tmp = *(tmp + 1);
		++tmp;
	}
	--_finish;
	return pos;
}

push_back()

功能:尾插数据

void push_back(const T& t)
{
	//原始写法
	/*if (_finish == _endofstoage)
	{
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
	}
	*_finish = t;
	++_finish;*/

	//复用insert函数
	insert(end(), t);
}

pop_back()

功能:尾删数据

void pop_back()
{
    //直接写法
	/*if (_finish > _start)
	{
		--_finish;
	}*/

    //复用erase()函数
    erase(end());
}

迭代器失效问题

上面在实现insert函数和erase函数时返回值都不是void,而是返回迭代器,原因就在于空间的改变可能会导致原先的迭代器仍旧指向旧空间,而旧空间在被释放之后就不允许访问了,所以迭代器就失效了,需要重新赋值指向现有空间。

1.扩容导致空间改变的失效问题:

图解:

那么insert导致的失效是空间改变的问题,erase可没有改变空间的操作啊,erase既不扩容也不缩容,为什么也要考虑迭代器失效的问题呢? 

首先,我们得考虑不同的平台对于迭代器失效的检查方式是不一样的,对于有些平台来说,迭代器指向空间的意义发生变化也会认为是迭代器失效。例如erase删除一个数据后,迭代器自然就指向了被删除数据的下一个数据。当然也不排除实现者erase之后就是要缩容等等之类的,综合来讲,我们要将这种情况可看成是迭代器失效的问题来处理。

2.指向意义发生变化导致失效

图解:

 []访问操作符

T& operator[](size_t pos)  //返回值:T&,为了支持修改 
{
	assert(pos < size());
	return *(_start + pos);
}

//const版本
const T& operator[](size_t pos) const
{
	assert(pos < size());
	return *(_start + pos);
}

构造函数

无参构造

vector()
	:_start(nullptr)
	,_finish(nullptr)
	,_endofstoage(nullptr)
{}

迭代器区间构造

template<class inputIterator>
vector(inputIterator left, inputIterator right)
	:_start(nullptr)
	,_finish(nullptr)
	,_endofstoage(nullptr)
{
	while (left < right)
	{
		push_back(*left);//调用尾插函数
		++left;
	}
}

vector(const size_t n, const T& val = T())

vector(const size_t n, const T& val = T())
	:_start(nullptr)
	, _finish(nullptr)
	, _endofstoage(nullptr)
{
	reserve(n);//开辟空间,一步到位
	for (size_t i = 0; i < n; ++i)
	{
		push_back(val);
	}
}

拷贝构造函数

vector(const vector<T>& v)
	:_start(nullptr)
	, _finish(nullptr)
	, _endofstoage(nullptr)
{
	vector tmp(v.begin(), v.end());//复用了迭代器区间构造函数
	swap(tmp);//交换this与tmp的内容
}

析构函数

~vector()
{
	if (_start)
	{
		delete[] _start;
		_start = _finish = _endofstoage = nullptr;
	}
}

swap()

功能:交换内容

void swap(vector<T>& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_endofstoage, v._endofstoage);
}

= 重载

功能:赋值(深度赋值)

vector<T>& operator=(vector<T> v)
{
	swap(v);
	return *this;
}

小结

vector的重点函数已经讲完,大部分的内容与string相似,学习和使用时可以互相参考。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值