C++模拟实现vector

一、定义my_vector类

  此处标明:以下成员函数都是写在my_list类内部的

#include<iostream>
#include<assert.h>

using namespace std;

template<class T>
class my_vector
{
public:
	//构造函数
	
	//赋值运算符重载
	
	//析构函数
	
	//迭代器
	typedef T* iterator;
	typedef const T* const_iterator;

	//Capacity

	//element access
	
	//modify
	
private:
	iterator _start;   //首元素地址
	iterator _finish;    //最后一个元素下一个位置地址
	iterator _end_of_storage;    //空间尾地址
};

二、成员函数实现

(一)构造函数

  1、无参构造

	my_vector()
		:_start(nullptr)
		, _finish(nullptr)
		, _end_of_storage(nullptr)
	{}

  2、n个value构造

	my_vector(size_t n, const T& val = T())
	{
		//开空间
		_start = new T[n];
		
		//赋值
		size_t i = 0;
		while (i < n)
		{
			_start[i] = val;
			i++;
		}
		
		_finish = _end_of_storage = _start + n;
	}

  3、迭代器构造
    因为这里的迭代器是一个泛型的迭代器,有可能迭代器内部没有实现减法的功能,所以这里就通过迭代器遍历然后尾插的操作来实现迭代器构造

	template<class InputIterator>
	my_vector(InputIterator first, InputIterator last)
	{
		//first和last都是泛型迭代器,并不一定支持相减的操作,所以用迭代器遍历尾插操作构造
		_start = new T;
		while (first != last)
		{
			push_back(first);
			first++;
		}
	}

  构造实例:

	void test()
	{
		int arr[5] = {1, 2, 3, 4, 5};
		my_vector<int> v(arr, arr + 5);
	}

(二)拷贝构造

	my_vector(const my_vector<T>& v)
	{
		size_t sz = v.size();
		size_t cap = v.capacity();
		//开空间
		T* tmp = new T[cap];

		//深拷贝
		size_t i = 0;
		while (i < sz)
		{
			tmp[i] = v[i];
			i++;
		}

		_start = tmp;
		_finish = _start + sz;
		_end_of_storage = _start + v.capacity();
	}

  在将拷贝对象的内容拷贝到构造对象时,因为对象类型可能是自定义类型,所以不能使用memcpy来进行浅拷贝,而是要用循环赋值的方式进行深拷贝

(三)赋值运算符重载

	my_vector<T>& operator=(my_vector<T> v)
	{
		Swap(v);

		return *this;
	}

  首先在接收参数时发生了一次拷贝构造,再将形参与对象本身进行交换,完成了一次深拷贝,函数结束时调用析构将形参析构,这样就完成了一次赋值;

(四)析构函数

	~my_vector()
	{
		if (_start)
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}
	}

(五)迭代器

	//迭代器
	typedef T* iterator;
	typedef const T* const_iterator;

	iterator begin()
	{
		return _start;
	}

	iterator end()
	{
		return _finish;
	}

	const_iterator cbeign() const
	{
		return _start;
	}

	const_iterator cend() const
	{
		return _finish;
	}

(六)容量相关

  1、获取有效元素个数size
    因为 _finish 指向最后一个元素的下一个位置,_start指向首元素位置,所以两个的差值就是有效元素个数;

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

  2、获取最大有效元素容量capacity
    同理,_end_of_storage指向空间末尾位置,所以与 _start 的差值就是空间的容量;

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

  3、增加空间总容量reserve
    在增容时,先判断新增的容量是否大于原有空间的容量,如果小于,则不进行增容;
    如果大于则进行以下操作:

		(1)开空间
		(2)将原有空间内容拷贝到新空间
		(3)销毁原有空间
		(4)改变指针指向
	//reserve
	void reserve(size_t new_capacity)
	{
		if (new_capacity > capacity())
		{
			size_t sz = size();
			//开空间
			T* tmp = new T[new_capacity];

			//深拷贝
			size_t i = 0;
			while (i < sz)
			{
				tmp[i] = _start[i];
				i++;
			}

			//释放原有空间
			delete[] _start;

			//改变指向
			_start = tmp;
			_finish = _start + sz;
			_end_of_storage = _start + new_capacity;
		}
	}

  4、改变有效字符个数resize
    改变有效字符个数分为以下几种情况:

(1)当newSize > size时,将新加的空间赋上传入的值;
(2)当newSize > capacity时,reserve增容,再赋值;
(3)当newSize < size时,直接改变_finish指针;
	//resize
	void resize(size_t new_size, const T& val = T())
	{
		if (new_size > size())
		{
			if (new_size > capacity())
			{
				reserve(new_size);
			}

			iterator it = end();
			while (it != _start + new_size)
			{
				*it = val;
				it++;
			}
		}

		_finish = _start + new_size;
	}

(七)Element Access

  []运算符重载

  1、非const修饰的[]运算符重载函数
    在获取index位置的值之前,需要判断边界,看是否越界访问;
    非const修饰的可以访问,也可以修改内容;

	T& operator[](size_t index)
	{
		//判断边界
		assert(index < size());

		return _start[index];
	}

  2、const修饰的[]运算符重载
    const修饰的可以访问但是不能修改内容

	const T& operator[](size_t index) const
	{
		//判断边界
		assert(index < size());

		return _start[index];
	}

(八)修改modify

  1、交换函数Swap

	void Swap(my_vector<T>& v)
	{
		swap(_start, v._start);
		swap(_finish, v._finish);
		swap(_end_of_storage, v._end_of_storage);
	}

  2、任意位置前插入一个值insert
    插入前首先要判断边界条件和是否需要扩容;

	//任意位置前插入
	iterator insert(iterator pos, const T& val)
	{
		//判断边界
		assert(pos >= begin() && pos <= end());

		//获取pos的偏移量
		size_t len = pos - _start;

		if (_finish == _end_of_storage)
		{
			size_t new_capacity = (_start == nullptr ? 1 : capacity() * 2);
			reserve(new_capacity);
		}

		iterator it = end();
		//更新pos的位置,防止增容之后pos失效
		pos = _start + len;

		while (it != pos)
		{
			*it = *(it - 1);
			it--;
		}

		*pos = val;
		_finish++;

		return pos;
	}

    因为传入的位置是迭代器,所以当增容时,会使迭代器失效,那么就必须要更新pos的位置,防止增容之后pos迭代器失效导致出现错误;
    返回值也是一个迭代器,返回的是pos位置的迭代器,指向的就是新加入的元素的位置,这也是防止在插入元素时迭代器失效的问题;
  3、删除任意位置元素erase

	//删除任意位置
	iterator erase(iterator pos)
	{
		//判断边界
		assert(pos >= begin() && pos < end());

		iterator it = pos + 1;

		while (it != end())
		{
			*(it - 1) = *it;
			it++;
		}

		_finish--;

		return pos;
	}

    同插入,删除的返回的也是pos位置的迭代器,指向的就是删除之前下一个元素的位置,这也是防止在插入元素时迭代器失效的问题;
  4、尾插,尾删
    尾插(push_back)、尾删(pop_back)都是inserterase两个函数的复用;

	//尾插
	void push_back(const T& val)
	{
		insert(_finish, val);
	}

	//尾删
	void pop_back()
	{
		erase(_finish - 1);
	}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值