【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的使用更加熟練,同時也掌握了底層原理,對我的代碼能力也是一種提升,初學難免會有錯誤,您發現錯誤,歡迎留言。

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