《STL系列》之vector原理及實現
最近忙得蛋疼,但還是想寫點屬於自己的東西。也不知道寫點啥,最後決定試著自己實現STL中常用的幾個集合,一來加深自己對STL的理解,二來看看自己是否有這個能力實現。實現目標就是:1能和STL相容;2最大化的實現STL中的介面並保持一致。即將STL中的集合換成我寫的也能用。這篇部落格介紹的是vector的原理及實現。
先把vector的大致實現說一下,後面會給出完整的原始碼。
新增元素:Vector通過一個連續的陣列存放元素,如果集合已滿,在新增資料的時候,就要分配一塊更大的記憶體,將原來的資料複製過來,釋放之前的記憶體,在插入新增的元素。插入新的資料分在最後插入push_back和通過迭代器在任何位置插入,這裡說一下通過迭代器插入,通過迭代器與第一個元素的距離知道要插入的位置,即int index=iter-begin()。這個元素後面的所有元素都向後移動一個位置,在空出來的位置上存入新增的元素。
void insert(const_iterator iter,const T& t ) { int index=iter-begin(); if (index<size_) { if (size_==capacity_) { int capa=calculateCapacity(); newCapacity(capa); } memmove(buf+index+1,buf+index,(size_-index)*sizeof(T)); buf[index]=t; size_++; } }
刪除元素:刪除和新增差不多,也分兩種,刪除最後一個元素pop_back和通過迭代器刪除任意一個元素erase(iter)。通過迭代器刪除還是先找到要刪除元素的位置,即int index=iter-begin();這個位置後面的每個元素都想前移動一個元素的位置。同時我們知道erase不釋放記憶體只初始化成預設值。
刪除全部元素clear:只是迴圈呼叫了erase,所以刪除全部元素的時候,不釋放記憶體。記憶體是在解構函式中釋放的。
iterator erase(const_iterator iter) { int index=iter-begin(); if (index<size_ && size_>0) { memmove(buf+index ,buf+index+1,(size_-index)*sizeof(T)); buf[--size_]=T(); } return iterator(iter); }
迭代器iteraotr是STL的一個重要組成部分,通過iterator可以很方便的儲存集合中的元素.STL為每個集合都寫了一個迭代器, 迭代器其實是對一個指標的包裝,實現一些常用的方法,如++,--,!=,==,*,->等, 通過這些方法可以找到當前元素或是別的元素. vector是STL集合中比較特殊的一個,因為vector中的每個元素都是連續的,所以在自己實現vector的時候可以用指標代替,如typedef T* iterator;typedef const T* const_iterator,如果STL中的函式能方便的操作自己寫的集合,實現的迭代器最好繼承std::iterator<std::forward_iterator_tag,T>。我實現vector的迭代器大概是這個樣子:
template<typename T>
class viterator:public std::iterator<std::forward_iterator_tag,T>{}
後面會給出完整的程式碼,std::iterator<std::forward_iterator_tag,T>的原始碼如下:
template<class _Category, class _Ty, class _Diff = ptrdiff_t, class _Pointer = _Ty *, class _Reference = _Ty&> struct iterator { // base type for all iterator classes typedef _Category iterator_category; typedef _Ty value_type; typedef _Diff difference_type; typedef _Diff distance_type; // retained typedef _Pointer pointer; typedef _Reference reference; };
Iterator其中沒有任何成員,只是定義了一組型別,所以繼承它並不會讓你的struct變大,這組型別是STL的內部契約,STL中的函式假設每個迭代器都定義了這些型別,所以只要你的迭代器定義了這些型別,就可以和STL函式集合一起使用。
我的vector實現原始碼如下:
#ifndef _CVECTOR_H_ #define _CVECTOR_H_ namespace cth { class NoCopy { public: inline NoCopy(){} NoCopy(const NoCopy&); NoCopy& operator=(const NoCopy&); }; template<typename T> class viterator:public std::iterator<std::forward_iterator_tag,T> { public: viterator() { t=NULL; } viterator(T* t_) { t=t_; } viterator(const viterator& other) { t=other.t; } viterator& operator=(const viterator& other) { t=other.t; return *this; } viterator& operator++() { t++; return *this; } viterator operator++(int) { viterator iter=*this; t++; return iter; } viterator operator+(int count) { viterator iter=*this; iter.t+=count; return iter; } viterator& operator--() { t--; return *this; } viterator operator--(int) { viterator iter=*this; t--; return iter; } viterator operator-(int count) { viterator iter=*this; iter.t-=count; return iter; } int operator-(const viterator& other) { return t-other.t; } int operator-(const viterator& other)const { return t-other.t; } T& operator*() { return *t; } const T& operator*() const { return *t; } T* operator->() { return t; } const T* operator->() const { return t; } inline bool operator!=(const viterator& other) { return t!=other.t; } inline bool operator!=(const viterator& other)const { return t!=other.t; } inline bool operator==(const viterator& other) { return t==other.t; } inline bool operator==(const viterator& other)const { return t==other.t; } inline bool operator<(const viterator& other) { return t<other.t; } inline bool operator<(const viterator& other)const { return t<other.t; } inline bool operator<=(const viterator& other) { return t<=other.t; } inline bool operator<=(const viterator& other)const { return t<=other.t; } inline bool operator>(const viterator& other) { return t>other.t; } inline bool operator>(const viterator& other)const { return t>other.t; } inline bool operator>=(const viterator& other) { return t>=other.t; } inline bool operator>=(const viterator& other)const { return t>=other.t; } private: T* t; }; template<typename T> class cvector:public NoCopy { public: typedef viterator<T> iterator;//viterator<T>就是對一個指標的包裝,所以完全可以用T*代替viterator <T> typedef const viterator<T> const_iterator; //typedef T* iterator; //typedef const T* const_iterator; cvector() { initData(0); } cvector(int capa,const T& val=T()) { initData(capa); newCapacity(capacity_); for (int i=0;i<size_;i++) buf[i]=val; } cvector(const_iterator first,const_iterator last) { initData(last-first); newCapacity(capacity_); iterator iter=iterator(first); int index=0; while(iter!=last) buf[index++]=*iter++; } ~cvector() { if (buf) { delete[] buf; buf=NULL; } size_=capacity_=0; } void clear() { if (buf) erase(begin(),end()); } void push_back(const T& t) { if (size_==capacity_) { int capa=calculateCapacity(); newCapacity(capa); } buf[size_++]=t; } void pop_back() { if (!empty()) erase(end() - 1); } int insert(const_iterator iter,const T& t ) { int index=iter-begin(); if (index<=size_) { if (size_==capacity_) { int capa=calculateCapacity(); newCapacity(capa); } memmove(buf+index+1,buf+index,(size_-index)*sizeof(T)); buf[index]=t; size_++; } return index; } iterator erase(const_iterator iter) { int index=iter-begin(); if (index<size_ && size_>0) { memmove(buf+index ,buf+index+1,(size_-index)*sizeof(T)); buf[--size_]=T(); } return iterator(iter); } iterator erase(const_iterator first,const_iterator last) { iterator first_=iterator(first); iterator last_=iterator(last); while(first_<=last_--) erase(first_); return iterator(first_); } T& front() { assert(size_>0); return buf[0]; } T& back() { assert(size_>0); return buf[size_-1]; } T& at(int index) { assert(size_>0); return buf[index]; } T& operator[](int index) { assert(size_>0 && index>=0 && index<size_); return buf[index]; } bool empty() const { return size_==0; } int size() const { return size_; } int capacity() const { return capacity_; } iterator begin() { return iterator(&buf[0]); } iterator end() { return iterator(&buf[size_]); } private: void newCapacity(int capa) { capacity_=capa; T* newBuf=new T[capacity_]; if (buf) { memcpy(newBuf,buf,size_*sizeof(T)); delete [] buf; } buf=newBuf; } inline int calculateCapacity() { return capacity_*3/2+1 ; } inline void initData(int capa) { buf=NULL; size_=capacity_=capa>0?capa:0; } int size_; int capacity_ ; T* buf; }; struct Point { Point(int x_=0,int y_=0):x(x_),y(y_){} int x,y; }; bool operator<(const Point& p1,const Point& p2) { if(p1.x<p2.x) { return true; }else if(p1.x>p2.x) { return false; } return p1.y<p2.y; } void cvectorTest() { cvector<Point> vect; for (int i=0;i<10;i++) { Point p(i,i); vect.push_back(p); } cvector<Point>::iterator iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } iter=vect.begin()+5; vect.insert(iter,Point(55,55)); iter=vect.end()-3; vect.insert(iter,Point(77,77)); cout<<endl<<endl<<"插入兩個元素後:"<<endl; iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } std::sort(vect.begin(),vect.end()); cout<<endl<<endl<<"排序後:"<<endl; iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } vect.erase(vect.begin()+10); vect.erase(vect.begin()+10); cout<<endl<<endl<<"刪除之前新增的兩個元素"<<endl; iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } vect.clear(); cout<<endl<<endl<<"執行clear之後"<<endl; cout<<"size="<<vect.size()<<",capacity="<<vect.capacity(); cvector<Point> vect1; for (int i=10;i<20;i++) { Point p(i,i); vect1.push_back(p); } cout<<endl<<endl<<"從別的cvector複製資料:"<<endl; cvector<Point> vect2(vect1.begin(),vect1.end()); vect2.pop_back(); vect2.pop_back(); for(int i=0;i<vect2.size();i++) { cout<<"["<<vect2[i].x<<","<<vect2[i].y<<"], "; } cout<<endl; } } #endifView Code
例項程式碼級執行結果如下:
struct Point { Point(int x_=0,int y_=0):x(x_),y(y_){} int x,y; }; bool operator<(const Point& p1,const Point& p2) { if(p1.x<p2.x) { return true; }else if(p1.x>p2.x) { return false; } return p1.y<p2.y; } void cvectorTest() { cvector<Point> vect; for (int i=0;i<10;i++) { Point p(i,i); vect.push_back(p); } cvector<Point>::iterator iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } iter=vect.begin()+5; vect.insert(iter,Point(55,55)); iter=vect.end()-3; vect.insert(iter,Point(77,77)); cout<<endl<<endl<<"插入兩個元素後:"<<endl; iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } std::sort(vect.begin(),vect.end()); cout<<endl<<endl<<"排序後:"<<endl; iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } vect.erase(vect.begin()+10); vect.erase(vect.begin()+10); cout<<endl<<endl<<"刪除之前新增的兩個元素"<<endl; iter=vect.begin(); while (iter!=vect.end()) { cout<< "[" << iter->x << " " << iter->y <<"], "; ++iter; } vect.clear(); cout<<endl<<endl<<"執行clear之後"<<endl; cout<<"size="<<vect.size()<<",capacity="<<vect.capacity(); cvector<Point> vect1; for (int i=10;i<20;i++) { Point p(i,i); vect1.push_back(p); } cout<<endl<<endl<<"從別的cvector複製資料:"<<endl; cvector<Point> vect2(vect1.begin(),vect1.end()); vect2.pop_back(); vect2.pop_back(); for(int i=0;i<vect2.size();i++) { cout<<"["<<vect2[i].x<<","<<vect2[i].y<<"], "; } cout<<endl; }
之後還會有list,set,map等的實現,敬請期待......