vector才算是打開了泛型編程的大門,在之前的幾篇博客中你可以明顯看到vector的構造,等介面的引數多了一個templete,畢竟他可以存任何的資料型別,著篇博客會涉及到一些STL原始碼(讓我們看看大神是如何實作的),且依舊沿襲上篇博客,我只實作我覺得比較難的介面
文章目錄
- 1. 基本框架
- 0 help 函式
- 1 迭代器
- 2 建構式
- 3 modify
- 4 capacity
1. 基本框架
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4V1VAljf-1639720382918)(/Users/wuxiaobo/Library/Application Support/typora-user-images/image-20211213161351874.png)]](https://img.uj5u.com/2021/12/18/289270180852371.png)
原始碼中是用iterator 創建了三個變數,start(開始)finish(結尾) end_of_storage(容量(capacity))
經過上篇博客的洗禮iterator應該比較熟悉了吧,其實就是迭代器,但是vector底層是一個線性的結構也就是陣列,那么Iterator一個T*
0 help 函式
開空間,深拷貝,現代寫法
void Construction(size_t N=1)//開辟空間
{
N=N>capacity()?N:capacity()*2;
Vector<T>tmp(N);
for(int i =0;i<capacity();i++)
{
tmp[i]=start[i];
(tmp.finish)++;
}
swap(tmp, *this);
}
構造串列函式,每個建構式都要寫獨立封裝一個讓代碼更簡潔
void StructList(const size_t num)
{
start=new T[num+1];
finish=start;
end_of_storage=start+num+1;
}
1 迭代器
上面基礎結構有用的了迭代器那么我們優先事項這一塊
typedef int* iterator;
iterator begin()
{
return start;
}
iterator end()
{
return finish;
}
const iterator begin()const
{
return start;
}
const iterator end()const
{
return finish;
}
iterator rebegin()
{
return finish-1;//最后一個元素的前一個元素
}
iterator reend()
{
return start-1;//第一個元素的上一個元素的
}
2 建構式
默認構造
Vector(size_t num =5)
{
StructList(num);//構造串列函式
}
拷貝構造
vector(const vector<T>& v)//用另一個vector初始化
{
StructList(num);//構造串列函式
_start=new T[v.size()];
_finish=_endOfStorage=_start+v.size();
auto tmp=v._start;
for(int i=0;i<v.size();i++)
{
_start[i]=tmp[i];
}
}
賦值拷貝
void operator =(Vector<T>val)
{
swap(*this,val);
}
迭代器區間構造
也就是和stirng 不同的地方,且后面的容器基本都支持用迭代器區間初始化,泛型編程必備,現階段看這個實作和拷貝,用一個模版去推你是啥型別的迭代器
template <class InputIterator>
Vector(InputIterator first,InputIterator end)
{
Construction(end-first);
while(first!=end)
{
start=*first++;
}
finish=end-first;
}
3 modify
push_bakc
不難發現的與string對比起來基礎沒差,一樣沒有空間開空間,插入資料…………,但是這里資料型別是根據模版顯示實體化的 ,本質就是底層是物理的連續空間
void push_back(const T&val)//T看到了嗎,來咯泛型編程的第一個介面
{
if(finish>=end_of_storage)//開辟空間
{
Construction();
}
*finish=val;
finish++;
}
[]
沿襲string的傳統,[]需要多載倆個一個為const版的,一個為非const版本的,這一塊操作賦多載又又發揮了作用
代碼:
T& operator[](const size_t index)
{
return start[index];
}
const T& operator[](const size_t index)const
{
return start[index];
}
insert
這一塊涉及了一個知識叫做迭代器失效,請觀看這篇 iterator 博客,這里就不深入研究了,這兒有倆構造
- 常數作為下標
- 迭代器作為下標(實作方法一直上面的說了vector的迭代器就是一個指標)
const size_t&insert ( const size_t & pos,const T&val)
{
if(size()+1>=capacity())
{
Construction();
};
for(int i=size();i>pos;i--)
{
start[i]=start[i-1];
}
start[pos]=val;
finish++;
return pos++;//回傳下一個元素的下標
}
erase
const size_t&erast (const size_t& pos)
{
finish--;
int ret=pos;
int count=size()-ret-1;//需要挪動的次數
while(count--)
{
start[ret]=start[++ret];
}
return pos+1;//pos下一個位置的下標
}
因為底層是一個陣列,所以像這類insert與erase這種介面最好少用,復雜度太高(資料如果有幾億個資料然后頭叉)
4 capacity
size
這一塊稍微與string有些出入的是,他沒有用size和capacity去記錄,而是用指標去指向了末尾元算,但是幸運的是,他物理空間是連續的,且指標是可以減指標的(不理解請參考博主這篇博客),那么finish-start那不就得到元素的個數嗎
代碼:
size_t size()
{
return finish-start;
}
reserve
沿襲string,容器中的reserve基本都是大于capacity就開空間小于啥也不干
void reserve(size_t n)
{
if(n>capacity())//開辟空間
{
Construction(n);
}
}
resize
這個介面需要考慮三個條件
- 大于capacity,增容,并初始化
- 小于size,縮短finish為n的長度,不更改end_of_storage
- 在size<=N<=capacity,,初始化資料到N的位置
代碼:
void resize(size_t n,const T&numb)//原始碼中會構造一個預設值,這我們就直接不搞了
{
if(n<size())
{
finish=start+n;
}
else if(n>capacity())//開辟空間
{
Construction(n);
}
for(int i=size();i<n;i++)//初始化空間
{
*finish++=numb;
}
}
上面仔細看會發現vector中的引數一般都是模版引數,而string就是char,因為string就是為字符而生的,vector為大眾服務,后面的容器和vector一樣都是好同志為大眾服務
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/384324.html
標籤:其他
