C++之vector类的模拟实现

片头

嗨~小伙伴们,今天我们来一起学习关于C++的vector类的模拟实现,准备好了吗?咱们开始咯~


一、基本框架

namespace bit {
	template<class T>
	class vector {
	public:
		typedef T* iterator;
		typedef const T* const_iterator;// 针对const修饰的迭代器
	private:
		iterator _start;		  //指向数据块的开始
		iterator _finish;		  //指向有效数据的结尾
		iterator _end_of_storage; //指向存储容量的结尾
	};
}

我们定义了一个模板类,这里的vector三个成员均为迭代器,而Vector的迭代器是一个原生指针,我们这里为其定义别名iterator

私有成员:

		iterator _start;		 //指向数据块的开始
		iterator _finish;		 //指向有效数据的结尾
		iterator _end_of_storage;//指向存储容量的结尾

这些成员变量用于管理vector内部的动态数组

(1)_start:这是一个指针,指向分配给vector的内存区域的开始。这是数组的第一个元素。

(2)_finish:这个指针指向数组中最后一个实际存在的元素的下一个位置。这意味着它指向结束后的第一个元素,它用来表示存储在vector中的实际元素的结束。

(3)_end_of_storage:这个指针指向分配给vector的内存块的末尾。这不是最后一个有效元素的位置,而是整个内存块的结束位置,在这之后可能会有额外的未初始化空间,预留以实现当vector增长时无需重新分配整个数组


二、相关函数

(1)size();

获取有效元素的个数

//获取有效元素的个数		
		size_t size() {
			return _finish - _start;
		}

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

 (2)capacity();

获取容量的大小

//获取容量的大小		
		size_t capacity() {
			return _end_of_storage - _start;
		}

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

 (3)reserve(size_t n);

如果容量不足,就开辟空间

有同学肯定会说,那还不简单~ ,下面我们来示范错误代码

//如果当前容量不足,就开辟空间		
         void reserve(size_t n) 
		{
			//n大于实际的容量,那么开辟新空间
			if (n > capacity()) 
			{
				T* temp = new T[n];//重新申请一块新空间,能够存放n个有效数据
				memcpy(temp, _start, sizeof(T) * size());//将原来的数据拷贝到temp中
				delete[] _start;//释放旧空间
				_start = temp;	//将新空间的地址赋给_start
			}
			_finish = _start + size();//更新_finish
			_end_of_storage = _start + n;//更新_end_of_storage
		}

但是这里有一个很大的问题:原来的_start的地址被销毁了,temp赋值给_start,_start指向新的空间,但是_finish还是旧的_finish,而size()函数需要用_finish-_start,所以此时的size()是无效的。

怎么解决这个问题呢?我们可以先用一个变量oldsize把原来的size()保存,后面_finish直接使用oldsize即可。

改进代码(仍不完善)

//不完善的代码		
         void reserve(size_t n) 
		{	
			size_t oldsize = size();//使用oldsize变量将原来的size()保存
			if (n > capacity()) 
			{
				T* temp = new T[n];
				memcpy(temp, _start, sizeof(T) * size());
				delete[] _start;
				_start = temp;
			}
			_finish = _start + oldsize;//直接使用oldsize
			_end_of_storage = _start + n;
		}

我们知道,只有当传递过来的n大于capacity()时,才需要扩容;并且,只有当旧空间有值的时候,才需要拷贝到新空间中,否则不做处理。因此,还可以进行优化:

//优化版本	
    	void reserve(size_t n) 
		{	
			if (n > capacity())
			{
				size_t oldsize = size();//使用oldsize变量将原来的size()保存
				T* temp = new T[n];
				if (_start) //当_start存在的时候,进行拷贝
				{
					memcpy(temp, _start, sizeof(T) * size());
					delete[] _start;
				}
				_start = temp;
				_finish = _start + oldsize;//直接使用oldsize
				_end_of_storage = _start + n;
			}
		}

但是,我们举一个例子:

将vector实例化为string类,调用4次push_back函数都没有问题。

但是,调用第5次push_back函数时,就出现了乱码,这是为什么呢?

因为memcpy函数是浅拷贝,所以reserve函数里面的string* temp和原来的_start指向的是同一块空间。调用delete[] _start时,会调用析构函数,将原来空间释放。所以temp指向的是一块非法的空间,因此会报错。

怎么解决这个问题呢?我们可以使用深拷贝

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t oldsize = size();//使用oldsize变量将原来的size()保存
				T* temp = new T[n];
				if (_start) //当_start存在的时候,进行拷贝
				{
				//	memcpy(temp, _start, sizeof(T) * size());  //浅拷贝

					for (size_t i = 0; i < oldsize; i++)//深拷贝 
					{
						temp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = temp;
				_finish = _start + oldsize;//直接使用oldsize
				_end_of_storage = _start + n;
			}
		}

 或者是调用swap函数

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				siz
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值