C++ vector模拟实现

vector是一个顺序表,它支持任意类型的数据,因此需要用到模板。要注意迭代器可能失效的问题。

目录

一、迭代器

二、成员

三、构造函数

四、拷贝构造

五、析构函数

六、交换

七、运算符重载

1、[ ]运算符重载

2、赋值运算符重载

八、容量

1、扩容不填数据reserve

2、扩容填数据resize

 3、当前数据个数

4、当前容量个数

九、插入删除

1、某个位置插入

2、某个位置删除

3、尾插

十、完整代码


一、迭代器

template<class T> //类模板
typedef  T* iterator;
typedef const T* const_iterator;
		//迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		iterator begin() const
		{
			return _start;
		}
		iterator end() const 
		{
			return _finish;
		}
		
		
		//迭代器初始化
		template<class Inputiterator>
		vector(Inputiterator first, Inputiterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

vector它的迭代器是一个指针。

迭代器初始化就是用一段迭代器区间去初始化, 也就是说可以用任意的迭代器区间去初始化它。

二、成员

private:
		iterator _start = nullptr;//指向数据起始位置
		iterator _finish = nullptr;//指向有效数据的尾
		iterator _endOfStorage = nullptr;//指向有效空间的尾

 它的成员是三个指针,我们可以直接给上缺省值nullptr,这样构造函数会写起来很方便。当然在这个地方也可以用两个整形,_size和_capactiy。

_finish - _start就是当前数据个数,_enOfStorage - _start就是当前容量大小。

三、构造函数

//构造n个空间,并填值	
   vector(size_t n,const T& val = T())
		{
			resize(n, val);
		}

	vector(int n, const T& val = T())
		{
			resize(n, val);
		}
//默认构造
    vector()
		{}

 在这个地方构造函数可以不用写初始化列表,C++11打了补丁,成员给缺省值,初始化的时候会按照成员缺省值初始化。这个地方主要看一下第一个构造函数,这个构造函数和resize的功能一样,我们直接调用resize来完成构造即可。要注意val的缺省值是一个匿名对象,如果是自定义类型会去调用自定义类型的构造函数来做缺省值,如果是内置类型也会调用内置类型的构造函数。内置类型也是可以用构造函数初始化的。

四、拷贝构造

//拷贝构造
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{
			_start = new T[v.capacity()];
			//memcpy(_start, v._start, sizeof(T) * v.size());
			for (size_t 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 (size_t i = 0; i < v.size(); i++)
			{
				push_back(v._start[i]);
			}
		}

这个地方拷贝构造可以复用reserve,直接开好要空间,再将值尾插进去即可。

也可以自己手写,这里要把成员全部处理一下,处理为nullptr,然后这个地方要注意的是拷贝数据不能用memcpy,否则如果vector内的数据是自定义类型就会出事。下面reserve会说。

五、析构函数

//析构
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endOfStorage = nullptr;
			}
			
		}

六、交换

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

 用库里的swap直接交换即可。

七、运算符重载

1、[ ]运算符重载

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

2、赋值运算符重载

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

 这个地方直接用swap即可。注意传参的时候不要用引用。

八、容量

1、扩容不填数据reserve

	void reserve(size_t n)
		{
			
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}
                    //这个地方如果是自定义类型,调用自定义类型的赋值重载
                    //如果是内置类型这样也没问题
					delete[] _start;
				}
				
				_start = tmp;
				_finish = _start + sz;
				_endOfStorage = _start + n;
				
			}
        }
	

在这个地方要注意 要先把size(),保存起来,不然扩容之后,_start指向的是新的空间,而_finish指向的还是旧空间,这样size()的结果就是不正确的。为什么这个地方不能用memcpy呢?看下面的代码

void test_vector5()
	{
		vector<string>v1;
		v1.push_back("11111");
		v1.push_back("22222");
		v1.push_back("33333");
		v1.push_back("44444");
 		v1.push_back("55555");
    } 

下面的代码每一个都是自定义类型,如果reserve用的是memcpy会出什么问题?

 就会出现上面的情况。也就是说vector是深拷贝,但是vector空间上存的对象是string的数组,memcpy就会导致string的对象浅拷贝。因此我们只能用上面的写法,上面的写法对自定义类型会调用它的赋值运算符重载,内置类型也没毛病。

2、扩容填数据resize

	//扩容
		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++;
				}
			}
		} 

在这个地方如果n大于数据个数,直接reserve一下,然后填数据即可。

 3、当前数据个数

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

4、当前容量个数

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

九、插入删除

1、某个位置插入

	void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			//扩容后pos有可能失效,因此计算相对位置。
			
			if (_finish == _endOfStorage)
			{
				size_t len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
				reserve(newcapacity);
				pos = _start + len;
			}
			
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}


			*pos = x;
			_finish++;
		}

这个地方要注意,扩容以后pos有可能失效,因此要先计算出pos和_start的面对位置,扩容之后再把pos更新。 

因为扩容不一定是原地扩容,异地扩容的话_start就变了,pos还是原来的_start,那么它就失效了,因此要更新它。

2、某个位置删除

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos <= _finish);
			iterator it = pos;
			while (it<= _finish)
			{
				*it = *(it + 1);
				it++;
			}
			_finish--;
			
			return pos;
		}

这个地方注意pos是迭代器位置,先判断pos合法性,然后直接覆盖即可,这里要返回pos位置的下一个数据的迭代器,也就是pos。

3、尾插

	void push_back(const T& x)
		{
            //自己写
			/*if (_finish == _endOfStorage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
				reserve(newcapacity);
			}
			
			*_finish = x;
			_finish++;*/
            //复用
			insert(end(), x);
		}

尾插可以直接写也可以直接复用insert。 

十、完整代码

#include<iostream>
#include<assert.h>
using namespace std;

namespace vae
{
	template<class T> //类模板

	class vector
	{
	public:
		typedef  T* iterator;
		typedef const T* const_iterator;
		//迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		iterator begin() const
		{
			return _start;
		}
		iterator end() const 
		{
			return _finish;
		}
		//构造
		
		//迭代器初始化
		template<class Inputiterator>
		vector(Inputiterator first, Inputiterator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		
		vector(size_t n,const T& val = T())
		{
			resize(n, val);
		}

		vector(int n, const T& val = T())
		{
			resize(n, val);
		}

		vector()
		{}
		//拷贝构造
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{
			_start = new T[v.capacity()];
			//memcpy(_start, v._start, sizeof(T) * v.size());
			for (size_t 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 (size_t i = 0; i < v.size(); i++)
			{
				push_back(v._start[i]);
			}
		}*/
		//析构
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endOfStorage;
			}
			
		}
		//扩容
		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 reserve(size_t n)
		{
			
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				
				_start = tmp;
				_finish = _start + sz;
				_endOfStorage = _start + n;
				
			}
        }
	
		void push_back(const T& x)
		{
			/*if (_finish == _endOfStorage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
				reserve(newcapacity);
			}
			
			*_finish = x;
			_finish++;*/
			insert(end(), x);
		}
	    
		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}
		const T& operator[](size_t pos)const
		{
			assert(pos < size());
			return _start[pos];
		}

		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			//扩容后pos有可能失效,因此计算相对位置。
			
			if (_finish == _endOfStorage)
			{
				size_t len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
				reserve(newcapacity);
				pos = _start + len;
			}
			
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}


			*pos = x;
			_finish++;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos <= _finish);
			iterator it = pos;
			while (it<= _finish)
			{
				*it = *(it + 1);
				it++;
			}
			_finish--;
			
			return pos;
		}

		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;
		}

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

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


	private:
		iterator _start = nullptr;//指向数据起始位置
		iterator _finish = nullptr;//指向有效数据的尾
		iterator _endOfStorage = nullptr;//指向有效空间的尾
	};
	void test_vector1()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		//v1.push_back(5);

		//mrl::vector<int> v2(v1);
		//for (auto& e : v1)
		//{
		//	e += 1;
		//}
		v1.insert(v1.begin(), 100);
		vector<int>::iterator p = v1.begin() + 3;
		//这个地方要注意,迭代器有可能失效(扩容)!!
		//insert之后就不能使用这个形参迭代器,因为它可能失效了
		v1.insert(p, 20);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test_vector2()
	{
		vector<int>v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);

		vector<int>v2(v1);
		
		v1.insert(v1.end(),100);

	     v1.swap(v2);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		for (auto e : v2)
		{
			cout << e << " ";
		}
		cout << endl;

	}

	void test_vector3()
	{
		vector<int>v1;
		v1.push_back(2);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		v1.push_back(6);

		auto it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				it = v1.erase(it);
			}
			else
			{
				++it;
			}
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_vector4()
	{
		vector<int>v1;
		v1.resize(10, 0);

		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<int>v2;
		v2 = v1;
		for (auto e : v2)
		{
			cout << e << " ";
		}
	}

	void test_vector5()
	{
		vector<string>v1;
		v1.push_back("11111");
		v1.push_back("22222");
		v1.push_back("33333");
		v1.push_back("44444");
 		v1.push_back("55555");
		vector<string>v2(v1);


		for (auto& e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
		for (auto& e : v2)
		{
			cout << e << " ";
		}
		cout << endl;

	}
	void test_vector6()
	{
		vector<int>v1(10, 1);

		for (auto& e : v1)
		{
			cout << e << " ";
		}
		cout << endl;


	}
}


int main()
{
	// mrl::test_vector1();
	 vae::test_vector6();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值