[C++入门]---vector深度剖析及模拟实现

本文详细介绍了C++STL中的vector类,包括其成员变量定义、构造函数、迭代器、大小和容量函数、索引操作、动态内存管理(reserve和resize)、插入和删除元素(insert和erase)、尾部操作(push_back,pop_back)以及拷贝构造、赋值运算符重载和析构函数。
摘要由CSDN通过智能技术生成

1. vector功能函数模拟实现

vector成员变量定义

template<class T>
class vector
{
typedef T* iterator;
typedef const T* const_iterator;
private:
	iterator _start = nullptr;//指向vector第一个数据的位置
	iterator _finish = nullptr;//指向vector最后一个数据的下一个位置
	iterator _endofstorage = nullptr;//记录最大存储容量的下一个位置
}

template<class T>使用类模板,来支持vector类实现不同类型的数组;②通过typedef将对应类型的源生指针实现成vector的迭代器iterator;③自定义类型的成员变量会调用默认构造函数进行初始化,而内置类型的成员变量,不同的编译器实现方式不同,默认内置类型的成员变量为随机值;④C++11中针对内置类型成员不初始化的缺陷打了补丁,即内置类型成员变量在类中声明时可以给默认值;⑤为了避免内置类型成员为随机值带来的错误,给声明成员变量赋值为nullptr
在这里插入图片描述

vecor构造函数

//构造函数
vector()
	:_start(nullptr)
	, _finish(nullptr)
	, _endofstorage(nullptr)
{}

构造函数中使用初始化列表进行初始化

vector迭代器

typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
	return _start;
}
iterator end()
{
	return _finish;
}
const_iterator begin()const
{
	return _start;
}
const_iterator end()const
{
	return _finish;
}

begin()获取第一个数据位置的iteratorend()获取最后一个数据下一个位置的iterator,分别针对普通vector对象、const vector对象事项不同的begin()\end()函数。在这里插入图片描述

vector的size函数

size_t size()const
{
	return _finish - _start;
}

[_start,_finish)为左闭右开区间,_finish - _startvector有效数据个数。

vector的capacity函数

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

[_start,_endofstorage)为左闭右开区间,_endofstorage - _startvector的存储容量。

vector的operator[]函数

T& operator[](size_t pos)
{
	assert(pos < size());
	return _start[pos];
}
const T& operator[](size_t pos)const
{
	assert(pos < size());
	return _start[pos];
}

针对不同对象实现不同版本的operator[]函数,判断pos位置是否在有效数据范围内。
在这里插入图片描述

vector的reserve函数

void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t sz = size();
		T* tmp = new T[n];
		if (_start)
		{
			//memcpy对自定义类型进行的为浅拷贝
			//memcpy(tmp, _start, sizeof(T) * sz);
			//扩容的时候带来的,vector<自定义类型>带来的深拷贝问题
			for (int i = 0; i < size(); i++)
			{
				tmp[i] = _start[i];
			}
			delete[] _start;
		}
		_start = tmp;
		_finish = _start + sz;
		_endofstorage = _start + n;
	}
}

①使用if语句判断是否需要扩容,避免了缩容带来的效率降低;②使用new开辟n个T类型的空间;③如果vextor不是首次扩容,则需要拷贝数据,使用memcpy函数对内置类型数据进行浅拷贝效率很高,但是对自定义数据进行浅拷贝,会出现析构两次、空间通用的错误,需要使用for循环进行一对一赋值,若数据为内置类型,进行正常的赋值,若数据为自定义类型,则会调用该自定义类型的赋值运算符重载函数进行深拷贝,delete[] _start;可以释放vector空间⑤最后使用tmp\sz\n对扩容的地址_start\_finish\_endofstorage进行更新。
在这里插入图片描述

vector的resize函数

//调整vector的size()
void resize(size_t n, const T& val = T())
{
	if (n < size())
	{
		_finish = _start + n;
	}
	else
	{
		reserve(n);
		while (_finish != _start + n)
		{
			*_finish = val;
			_finish++;
		}
	}
}

使用if语句判断,n小于vector原有数据个数,直接对_finish位置进行更改;n大于vector原有数据个数,进行扩容后再进行赋值拷贝!

vector的insert函数

iterator insert(iterator pos, const T& x)
{
	assert(pos >= _start && pos <= _finish);
	if (_finish == _endofstorage)
	{
		//记录pos位置与_start位置的距离
		int len = pos - _start;
		size_t newcapacity = capacity() == 0 ? 3 : capacity() * 2;
		reserve(newcapacity);
		//解决迭代器失效问题
		pos = _start + len;
	}

	T* end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		end--;
	}
	*pos = x;//自定义类型会调用赋值运算符重载函数
	_finish++;
	return pos;
}

①使用assert判断pos位置是否和合法;②判断是否需要扩容,如果需要扩容,则需要记录pos位置与_start位置的距离,重新扩容后,_start指向新的空间,pos位置还指向已经释放掉的原有空间的位置,需要更新内部pos位置,解决内部pos迭代器失效问题;③挪动插入数据,返回pos的迭代器指向。

eg:

void Testinsert()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	//在insert外部使用pos记录位置
	vector<int>::iterator pos = v.begin();
	//使用pos位置进行插入
	v.insert(pos, 100);
	//再次对pos位置的数据进行操作
	*pos += 10;
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

VS结构下代码编译运行的结果为:
在这里插入图片描述
g++结构下编译的结果为:
在这里插入图片描述
总结:

①使用insert函数在pos位置迭代器插入数据,继续访问pos位置的数据,如果扩容这个pos位置的迭代器失效了;②在VS编译器上直接报错,在g++上正常运行;③如果要继续访问pos位置的数据,需要接收insert函数返回迭代器(即给it重新赋值即可)。

vector的erase函数

//任意删除
iterator erase(iterator pos)
{
	assert(pos >= _start && pos < _finish);
	iterator it = pos + 1;
	while (it != _finish)
	{
		*(it - 1) = *it;
		it++;
	}
	_finish--;
	return pos;
}

①判断删除的pos位置是否合法;②使用it记录pos下一个位置,然后挪动数据覆盖进行删除数据;③返回删除位置的迭代器。

eg:

void Testerase()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
		{
			v.erase(it);
		}
		else
		{
			it++;
		}
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
}

VS结构下代码编译运行的结果为:
在这里插入图片描述

g++结构下编译的结果为:
在这里插入图片描述
总结:

①使用erase函数在pos位置迭代器删除数据,需要继续访问pos位置的数据,如果删除的pos位置的数据为最后一个数据,删除后该迭代器不属于有效范围,即迭代器失效了;②在VS编译器上直接报错,在g++上一般会正常运行;③如果要继续访问pos位置的数据,需要接收erase函数返回迭代器。(即给it重新赋值即可)。

vector的push_back函数

void push_back(const T& x)
{
	//方法一:
	//判断是否需要扩容
	if (_finish == _endofstorage)
	{
		size_t newcapacity = capacity() == 0 ? 3 : capacity() * 2;
		reserve(newcapacity);
	}
	*_finish = x;//自定义类型会调用赋值运算符重载函数
	_finish++;
}
void push_back(const T& x)
{
	//方法二:
	insert(end(), x);
}

使用if语句进行判断是否需要扩容,直接在_finish插入数据,更新_finish位置。

vector的pop_back函数

void pop_back()
{
	erase(end()-1);
}

使用erase函数进行尾删

vector的拷贝构造函数

方法一:

vector(const vector<T>& v)
{
	_start = new T[v.size()];
	//memcpy(_start, v._start, sizeof(T) * sz);
	for (int i = 0; i < v.size(); i++)
	{
		_start[i] = v._start[i];
	}
	_finish = _start + v.size();
	_endofstorage = _start + v.capacity();
}

方法二:

vector(const vector<T>& v)
{
	reserve(v.size());
	for (auto e : v)
	{
		push_back(e);
	}
}

拷贝构造函数方法一:开辟vector拷贝构造对象的相同空间,如果vector存储的数据类型为自定义类型,使用到memcpy函数会浅拷贝,需要使用for循环进行赋值,如果vector存储的数据类型为内置类型,则为正常的赋值;如果vector存储的数据类型为自定义类型,则会调用赋值运算符重载函数进行深拷贝。拷贝构造函数方法二:使用reserve函数开辟空间,使用范围forvector尾插函数push_back进行尾插vector拷贝构造对象的数据。

//使用n个val值初始化数组
vector(size_t n, const T& val = T())
{
	resize(n, val);
}
//针对vector<int,int>实现
vector(int n, const T& val = T())
{
	resize(n, val);
}

vector拷贝构造函数的形参const T& val = T()T()如果T类型为内置类型则val为编译器使用默认值;如果T类型为自定义类型,则会调用默认构造函数。

//使用vector的迭代区间进行初始化--左闭右开
//template<class IputIterator>
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		first++;
	}
}

使用push_back函数插入拷贝构造对象迭代器区间的数据。

vector的operator=运算符重载函数

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)
{
	swap(v);
	return *this;
}

在运算符重载函数的形参会调用拷贝构造函数构造一个vector对象v,使用swap函数交换两个vector对象私有成员变量后,vector对象v指向旧空间(this原指向的空间),在operator=函数结束时会主动释放。

vector的析构函数

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

析构函数释放_start指向的空间,将_start\_finish\_endofstorage进行置空。

2.vector.h文件

#include<assert.h>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
namespace hhl
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin()const
		{
			return _start;
		}
		const_iterator end()const
		{
			return _finish;
		}
		//构造函数
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{}

		//拷贝构造 v1(v2)
		//vector(const vector<T>& v)
		//{
		//	_start = new T[v.size()];
		//	//memcpy(_start, v._start, sizeof(T) * sz);
		//	for (int i = 0; i < v.size(); i++)
		//	{
		//		_start[i] = v._start[i];
		//	}
		//	_finish = _start + v.size();
		//	_endofstorage = _start + v.capacity();
		//}
		vector(const vector<T>& v)
		{
			reserve(v.size());
			for (auto e : v)
			{
				push_back(e);
			}
		}
		//使用n个值初始化数组
		vector(size_t n, const T& val = T())
		{
			resize(n, val);
		}
		vector(int n, const T& val = T())
		{
			resize(n, val);
		}
		//使用vector的迭代区间进行初始化--左闭右开
		//template<class IputIterator>
		//vector(IputIterator first, IputIterator last)
		//{
		//	size_t n = last - first;
		//	_start = new T[n];
		//	int i = 0;
		//	while (first != last)
		//	{
		//		_start[i] = *first;
		//		i++;
		//		first++;
		//	}
		//	_finish = _start + n;
		//}
		// [first, last)
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}				
		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)
		{
			swap(v);
			return *this;
		}
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, sizeof(T) * sz);
					//扩容的时候带来的,vector<自定义类型>带来的深拷贝问题
					for (int i = 0; i < size(); i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}
		}
		void resize(size_t n, const T& val = T())
		{
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);
				while (_finish != _start + n)
				{
					*_finish = val;
					_finish++;
				}
			}
		}
		void push_back(const T& x)
		{
			//方法一:
			//判断是否需要扩容
			if (_finish == _endofstorage)
			{
				size_t newcapacity = capacity() == 0 ? 3 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			_finish++;
			//方法二:
			insert(end(), x);
		}
		//复用erase函数
		void pop_back()
		{
			erase(end()-1);
		}
		//void insert(iterator pos,const T& x)
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			if (_finish == _endofstorage)
			{
				//记录pos位置与_start位置的距离
				int len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 3 : capacity() * 2;
				reserve(newcapacity);
				//解决迭代器失效问题
				pos = _start + len;
			}

			T* end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}
			*pos = x;
			_finish++;
			return pos;
		}
		//任意删除
		iterator erase(iterator pos)
		{
			//assert(pos >= _start && pos < _finish);
			iterator it = pos + 1;
			while (it != _finish)
			//while (it <= _finish)
			{
				*(it - 1) = *it;
				it++;
			}
			_finish--;
			return pos;
		}
		size_t size()const
		{
			return _finish - _start;
		}
		size_t capacity()const
		{
			return _endofstorage - _start;
		}
		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}
		const T& operator[](size_t pos)const
		{
			assert(pos < size());
			return _start[pos];
		}
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _endofstorage = nullptr;
	};
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值