自己動手寫vector

    最近學習c++的STL,把STL中的vector自己寫了一下,寫的過程中對c++進行學習。

主要的幾個模塊:

 (1)構造析構函數、拷貝構造和賦值函數(類的幾個基本函數)
(2)增加、刪除函數
(3)遍歷函數
(4)大小及判空函數
(5)其它(swap或者assign)

// MyVector.cpp : 定義控制檯應用程序的入口點。
/*******************我的Vector實現*********************************
**功能:自己動手寫stl中的vector
**作者:謝凡凡
****************************************************/
#include "stdafx.h"
#include <iostream>
#include <assert.h>

using namespace std;

//vector類模板
template <class T>
class MyVector
{
public:
	typedef T* iterator;           //迭代器類型
	typedef T* pointer;
	typedef T & reference;
//構造函數
	MyVector():start(0),endx(0),end_of_storage(0),nsize(0),ncapacity(0){}             //列表初始化  默認的構造函數
	MyVector(int nSize,const T& val)                     //n個元素,且初始化爲val
	{
		if (!nSize)
		{
			start = 0;
			endx = 0;
			end_of_storage = 0;
			nsize = 0;
			ncapacity = 0;
		}
		else
		{
			int iTotalLen = 1;
			while (iTotalLen < nSize)                     //空間大小是2倍增長
			{
				iTotalLen *= 2;
			}
			start = new T[iTotalLen];                     //申請空間
			iterator start_cc = start;
			endx = start + nSize;
			end_of_storage = start + iTotalLen;
			nsize = nSize;
			ncapacity = iTotalLen;
			while(nSize--)
			{
				*start_cc++ = val;
			}
		}
	}
	MyVector(int nSize)                                       //n個元素,初始化爲0
	{
		if (!nSize)
		{
			start = 0;
			endx = 0;
			end_of_storage = 0;
			nsize = 0;
			ncapacity = 0;
		}
		else
		{
			int iTotalLen = 1;
			while (iTotalLen < nSize)
			{
				iTotalLen *= 2;
			}
			start = new T[iTotalLen];                     //申請空間
			iterator start_cc = start;                    //一份拷貝
			endx = start + nSize;
			end_of_storage = start + iTotalLen;
			nsize = nSize;
			ncapacity = iTotalLen;			
		}
	}
	MyVector(const MyVector& mv)                              //拷貝構造函數
	{
		if (this == &mv)
		{
			return ;
		}
		if (mv.empty())
		{
			start = 0;
			endx = 0;
			end_of_storage = 0;
			nsize = 0;
			ncapacity = 0;
		}
		else
		{
			int iTotalLen = mv.capacity();                            //當前容器最大容量
			int isize = mv.size();
			start = new T[iTotalLen];
			endx  = start + isize;
			end_of_storage = start + iTotalLen;
			nsize = isize;
			ncapacity = iTotalLen;
		}
	}

	~MyVector()                               //析構函數  注意對容器中的元素調用析構函數
	{
		iterator index;
		for (index = start;index < end_of_storage;++index)
		{
			index->~T();                       //調用容器中的元素的析構函數
		}
		delete [] start;
		start = NULL;
		endx  = NULL;
		end_of_storage = NULL;
		nsize = 0;
	}

	iterator begin() const                    //獲取起始迭代器
	{
		return start;
	}
	iterator end() const
	{
		return endx;
	}

	int size() const                              //返回容器中元素的個數
	{
		return nsize;       
	}
	void resize(int newSize,const reference x);       //調整容器尺寸
	int capacity() const                             //獲取容器最多可以存儲多少個元素
	{
		return ncapacity;
	}
	bool empty() const                               //容器是否爲空
	{
		return (start == endx);
	}
	reference operator[](int n)                      //對下標運算符進行重載,返回該位置的一個引用
	{
		assert(n >= 0 && n < ncapacity);
		return *(start + n);
	}
	reference operator=(const T& other)             //賦值運算符
	{
		if (this != &other)
		{
			if (other.empty())
			{
				this->clear();
			}
			else
			{
				if (ncapacity < other.capacity())                //左邊空間不夠  重新分配足夠的空間
				{
					start = new T[other.capacity()];
					endx  = start + other.nsize;
					end_of_storage = start + other.capacity();
					nsize = other.nsize;
					ncapacity = other.ncapacity;
					for (int index =0;index < nsize;++index)
					{
						*(start + index) = *(other.begin() + index);
					}
				}                                                //左邊有足夠空間  用原來的空間
				else
				{
					endx  = start + other.nsize;
					end_of_storage = start + other.capacity();
					nsize = other.nsize;
					ncapacity = other.ncapacity;
					for (int index =0;index < nsize;++index)
					{
						*(start + index) = *(other.begin() + index);
					}					
				}
			}
			return *this;
		}
	}
	reference front()                         //返回首元素引用
	{
		return *start;
	}
	reference back()                          //返回尾元素引用
	{
		return *(endx - 1);
	}
	reference at(int pos)                     //返回指定位置的一個引用  超出範圍應該拋出異常
	{
		if (pos >= 0 && pos < ncapacity)
		{
			return *(start + pos);
		}
		else                                   //拋出異常
		{
			throw out_of_range("MyVector out of range"); 
		}
	}

	void push_back(const T& x)                 //尾端插入
	{
		if (endx != end_of_storage)            //容器還有餘量
		{
			*endx = x;
			nsize = nsize + 1;
			endx++;
		}
		else                                   //容器沒有餘量,重新分配空間,並進行數據拷貝,然後刪除原來的空間
		{
			insert(end(),1,x);
		}
	}
	void insert(iterator it,const T& x)          //某一個元素前  增加一個元素x
	{
		insert(it,1,x);
	}
	void  insert(iterator it,int n,const T& x);       //某一個元素前  增加n個元素x
	void pop_back()                                   //刪除尾端元素
	{
		endx--;
		endx->~T();
		nsize--;
	}
	void erase(iterator pos)                          //刪除指定位置的元素
	{
		erase(pos,pos+1);
	}
	void erase(iterator _first,iterator _end)             //刪除範圍元素  [_first,_end)
	{
		int j = end() - _end;
		for (int index = 0;index < j;++index)             //後邊的元素前移
		{
			*(_first + index) = *(_end + index);
		}
		while(end() - _first > j)
		{
			pop_back();
		}
	}
	void clear()                                          //清除容器中的所有元素
	{
		erase(start,endx);
	}
	void swap(MyVector& other)                                   //交換數據
	{
		MyVector tem;
		tem = other;
		other = *this;
		*this = tem;
	}
	void assign(int n,const T& x)                  //給容器中某一個位置賦值
	{
		*(start + n - 1) = x;
	}
private:
	iterator start;                //指向數據區起始地址
	iterator endx;                 //指向數據區末尾地址
	iterator end_of_storage;       //指向容量的末尾,一般留有多餘的空間

	int nsize;                     //當前容器中元素個數
	int ncapacity;                 //容器可以存儲最多元素個數

};

template <class T>
void MyVector<T>::insert(iterator it,int n,const T& x)       //某一個元素前  增加n個元素x
{
	iterator old_start = start;               //原來的指針
	iterator old_endx = endx;
	iterator new_start;                       //不擴容的話  指向old_start,擴容的話指向new_start
	int numofmove = (endx - it);              //從it到endx中有多少個元素需要向後移動
	bool bNeedChange = false;
	if (endx + n > end_of_storage)            //剩餘空間不夠了
	{
		bNeedChange = true;
		const int old_size = size();
		const int len = old_size + n;        //加新的元素  有多少個元素
		int it1 = 1;
		while (it1 < len)
		{
			it1 *= 2;
		}

		start = new T[it1];
		endx = start + len;
		end_of_storage = start + it1;
		new_start = start;
		ncapacity = it1;
		nsize = len;
	}
	else
	{
		new_start = start;
		endx = endx + n;
		nsize = nsize + n;
	}
	iterator item = old_start;
	while (item < it)                  //拷貝原始數據
	{
		*new_start++ = *item++; 
	}
	iterator itend = endx;
	iterator old_endx_cc = old_endx;
	while (numofmove--)
	{
		*(--itend) = *(--old_endx_cc);
	}
	while (n--)                       //插入特定數據
	{
		*new_start++ = x;
	}
	if (bNeedChange)                 //需要釋放原始空間
	{
		while (old_start != old_endx)
		{
			old_start->~T();
			old_start++;
		}
	}
}



int _tmain(int argc, _TCHAR* argv[])
{
	struct Point
	{
		Point(){}
		Point(int a=0,int b=0):x(a),y(b){}
		int x,y;
	};


	cout<<sizeof(Point)<<endl;
	MyVector<Point>  myvec(3);
	cout<<myvec.size()<<endl;

	for (int i=1;i<3;++i)
	{
		Point ptem(i,2*i);
		myvec.push_back(ptem);
	}
	
	for (MyVector<Point>::iterator it = myvec.begin();it != myvec.end();++it)
	{
		cout<<it->x<<" "<<it->y<<endl;
	}

	return 0;
}

自己寫vector的一些感受:

(1)vector其實比string簡單
     string看似簡單,其實內部函數很多,而且有很多重載函數,實現不麻煩,但是很繁瑣。vector的函數較少,重載函數也不多,比較簡便。
(2)vector使用的c++模板技術
     這是我寫vector的目的之一,學習一下模板的用法,也沒那麼難。使用模板技術,則該容器可以存儲任意類型(包括內置類型和自定義類型)。
(3)對new運算符理解更深刻了
     vector底層數據結構是動態數組,長度可以自動增長,所以使用的new分配內存。new一個內置類型很容易理解(eg. int),但是new一個類對象或者類對象數組,就複雜些了。
     a.分配一塊足夠大的內存,足以存儲類對象或者類對象數組
     b.對類對象調用構造函數進行初始化
     c.返回一個指針,指向分配的內存塊
     這裏邊的調用構造函數對類對象初始化,很重要。


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