【C++学习笔记】----模拟实现vector容器(详解常见方法实现)

1.简介

概念:vector是一种可变大小的容器,物理上是一段连续的空间,和数组相比,它可以实现按需增长,十分好用,和list相比,vector可以直接访问任意位置的元素,不足的是,除尾插尾删之外的插入和删除,效率比较差。
结构:
在这里插入图片描述

2.代码展示

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
#include<string>
using namespace std;
namespace xff
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin() { return _start; }
		iterator end()	 { return _finish; }
		const_iterator cbegin()const { return _start; }	
		const_iterator cend()const	 { return _finish; }
		

		vector()
			:_start(nullptr)
			, _finish(nullptr)
			,_endofstorage(nullptr)
		{}
		vector(int n, const T& value = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			resize(n, value);
		}
		template<class Inputiterator>
		vector(Inputiterator first, Inputiterator last)
		{
			size_t newcapacity = last - first;
			reserve(newcapacity);
			while (last != first)
			{
				push_back(*first);
				++first;
			}
		}
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start =_finish =_endofstorage= nullptr;
			}
		}
		//v(v1)
		vector(const vector<T>& v)
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			reserve(v.capacity());
			auto it = begin();
			auto vit = v.cbegin();
			while (vit != v.cend())
			{
				*it++ = *vit++;
			}
			_finish = it;
		}
		//v=v1
		vector<T>& operator=(const vector<T>& v)
		{
			vector<T> v1(v);
			swap(v1);
			return *this;
		}
		//[]
		const T& operator[](size_t pos)
		{
			size_t oldsize = size();
			assert(pos < oldsize);
			return _start[pos];
		}
		const T& operator[](size_t pos)const { return _start[pos]; }
		void push_back(const T& x)
		{
			size_t oldcapactiy = capacity();
			size_t oldsize = size();
			if (oldsize == oldcapactiy)
			{
				size_t newcapacity = oldcapactiy == 0 ? 2 : 2 * oldcapactiy;
				reserve(newcapacity);
			}
			_start[oldsize++] = x;
			_finish = _start + oldsize;
		}
		const T front()const{return *_start;}
		const T back() {return *--_finish;}
		const size_t size()const{return _finish - _start;}
		const size_t capacity()const{return _endofstorage - _start;}
		bool empty()
		{
			if (_start == _finish)
				return true;
			return false;
		}
		void clear()
		{
			_finish=_start;
		}
		void pop_back()
		{
			if (_start != _finish)
				--_finish;
		}
		//
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}
		void reserve(size_t n)
		{
			size_t oldcapacity = capacity();
			if (oldcapacity<n)
			{
				T* newT = new T[n];
				size_t oldsize = size();
				for (int i = 0; i < oldsize; ++i)
				{
					newT[i] = _start[i];
				}
				_start = newT;
				_finish = newT + oldsize;
				_endofstorage = newT + n;
			}
		}
		void resize(size_t n, const T& value =T())
		{
			size_t oldsize = size();
			if (n > oldsize)
			{
				reserve(n);
				while (oldsize < n)
				{
					_start[oldsize++] = value;
				}
				_finish = _start + oldsize;
			}
			else
			{
				while (oldsize > n)
				{
					--oldsize;
				}
				_finish = _start + oldsize;
			}
		}
		iterator insert(iterator pos, const T& v)
		{
			assert(pos <= _finish);
			size_t oldsize = size();
			size_t oldcapactiy = capacity();
			size_t newsize = pos - _start;
			if (oldsize == oldcapactiy)
			{
				size_t newcapacity = oldcapactiy == 0 ? 2 : 2 * oldcapactiy;
				reserve(newcapacity);
				pos = _start + newsize;//
			}
			auto end = _finish - 1;
			while (end>=pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = v;
			++_finish;
			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos < _finish);
			auto begin = pos + 1;
			while (begin != _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}
			--_finish;
			return pos;
		}
	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};
	void test_vector_int()
	{
		vector<int> v;
		//v.resize(5);
		//v.reserve(10);
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);
		//v.pop_back();
		//vector<int> v1(v.begin(), v.end());
		vector<int> v2(v);
		vector<int> v3(6,6);
		//v.clear();
		//cout << v.front() <<" "<<v.back()<< endl;
		//v.swap(v3);
		//cout << v[0]<< endl;
		//v3 = v2;
		v.insert(v.begin() + 5, 6);
		v.insert(v.begin() + 6, 7);
		v.insert(v.begin() + 7, 8);
		v.insert(v.begin() + 8, 9);
		//v.erase(v.begin()+2);
		cout << v.size() << " " << v.capacity() << endl;
		//string s("hello");
		//vector<char> v4(s.begin(), s.end());
		for (auto e : v)
		{
			cout << e << " ";
		}
	}
	void test_vector_string()
	{
		vector<string> str;
		str.push_back("1111");
		str.push_back("2222");
		str.push_back("3333");
		str.push_back("4444");
		vector<string> str2(str);
		//str.pop_back();
		//cout << str.front() <<" "<< str.back() << endl;
		//str.reserve(10);
		//str.resize(1);
		//str.clear();
		//str.erase(str.begin()+1);
		//str.insert(str.begin()+str.size(), "a");
		//vector<string> str1(str.begin(), str.begin() + 2);
		//str.swap(str1);
		//cout << str.empty();
		cout << str.size() << " " << str.capacity() << endl;
		//str2 = str1;
		for (auto s : str)
		{
			cout << s << " ";
		}
		
	}
}


#include<vector>
void test_vector()
{
	string s("hello");
	vector<int> v{ 1,2,3,5,5 };
	vector<int> v1(2,8);
	//v.reserve(10);
	//v.resize(5);
	//v.push_back(9); 
	//cout << v.front() <<" "<<v.back()<< endl;
	//cout << v.size() <<" "<< v.capacity() << endl;
	//v.clear();
	//v.erase(v.begin(),v.begin()+2);
	//v.insert(v.end(),2);
	//v.swap(v1);
	//v.pop_back();
	//auto pos = find(v.begin(), v.end(), 5);
	//v.erase(v.begin());
	vector<char> v3(s.begin(), s.end());
	for (auto e : v3)
	{
		cout << e << " ";
	}
}

int main()
{
	//test_vector();
	xff::test_vector_int();
	//xff::test_vector_string();
	system("pause");
	return 0;
}

3.总结

vector的一些方法实现和string很类似。
但是,实现过程中我发现几个需要注意的点。
1.vector 不一定存储int类型的数据,所以我们要解决类型的问题。
2.由于类型的问题,我们在扩容的时候不能直接用拷贝函数,memcpy(dst,src,n),按字节拷贝,浅拷贝。自定义类型可能会出现错误,如果是string类型的话,值拷贝析构就出现问题了。
3.迭代器实际上就是原生指针,在构造函数那里,我们不限定是哪个容器的迭代器,如果直接用vector的话,就只能构造vector的对象中的一部分。
4.迭代器失效,由于插入删除都有可能导致迭代器失效,插入可能导致扩容,底层的指针改变了,所以会失效,删除的话,按理说不会失效,但是编译器在程序运行的过程中,检查到有空间的变化时就会失效,所以我在实现insert和erase的时候,只给了初始位置,当可能会失效时,重新将头指针指向心的空间。

通过自己实现vector容器,我对vector的使用更加熟练,同时也掌握了底层原理,对我的代码能力也是一种提升,初学难免会有错误,您发现错误,欢迎留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章