STL(Standard Template Library)
我們使用庫函數非常方便,且非常高效(相對於自己實現來說)。那如此好用的模板庫它的內里是什么樣的?它背着我們施展了什么“魔法”呢?我決定一探究竟,相信你也是一樣。我會選用部分重要代碼做分析,用來提升自己,希望后來的你在我的拙見中也能有自己的收獲。
vector
數據存儲方式:線性存儲(一塊連續內存),類似array。
相比於內置數組(不是array哦)的優勢:動態擴容。(其實也不算什么優勢,數組也完全可以做,只不過它把擴容過程高效安全地封裝了起來。)
相比於array,優勢就更大了,array的容量開始就是定死了的,無法擴容。
使用方法
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 // unique_ptr::get vs unique_ptr::release 7 int main() 8 { 9 //初始化 10 vector<int> vec;//聲明,未初始化 11 vector<int> vec1(2, 5);//2個5 12 vector<int> vec2 = { 1, 2, 3, 4, 5 };//直接初始化
13 //讀取元素 14 cout << "第2個元素: " << vec2[1] << endl; 15 cout << "首元素: " << vec2.front() << endl; 16 cout << "尾元素: " << vec2.back() << endl;
17 //插入元素 18 vec1.insert(vec1.begin(), 999);//para1-插入位置,要迭代器即指針,para2-插入內容 19 vec2.push_back(888);//尾部插入 20 vec2.pop_back();//刪除尾部,類似於stack,所以有時候也可以把vector當stack用
21 //刪除元素 22 vec2.erase(vec2.end()-1);//參數也是迭代器類型,所以使用insert和erase時,最好用iterator來遍歷
23 //排序 24 sort(vec2.begin(), vec2.end());//給出首位指針 25 sort(vec2.begin(), vec2.begin()+3);//甚至這樣也可以,因為iterator本身就是類型指針 26 27 //遍歷--下標索引訪問 28 cout << "vec1 : " ; 29 for (int i = 0; i < vec1.size(); ++i) 30 { 31 cout << vec1[i] << " "; 32 } 33 34 //遍歷--迭代器指針訪問 35 cout << "\nvec2 : "; 36 vector<int>::iterator it; 37 for (it=vec2.begin(); it != vec2.end(); ++it) 38 { 39 cout << *it << " "; 40 }
41 //使用指針遍歷vector
auto vec = new vector<int>(10, 8);
for(int i=0; i<vec->size(); i++)
cout << (*vec)[i] << " ";
41 return 0; 42 }
好了,基本的用法就是這樣。
底層是怎么實現的呢?
在STL源碼中,vector類維護有三個迭代器(三個類型指針)start, finish, end_of_storage, 分別代表頭, 尾(實際使用的), vector 存儲尾部(占用的,通常大於實際使用)。
當我們vector<TYPE>::iterator it;時,it就是TYPE* 類型指針,上述三個迭代器也是如此。
庫函數的實現呢?
我們可以看出,通過上述的三個指針,幾乎所有的操作都可以進行了。值得一提的是vector重載了[ ],可以方便存取值。
需要注意的是,當我們訪問尾元素時,迭代器可不是*.end(),而是*.end()-1。
那么我們再來探討一下,有意思的東西。
插入元素時,預設的end_of_storage不夠怎么辦?怎么進行擴容。
再看源碼!
整個的流程是:
1.先申請兩倍內存,判斷夠不夠,夠進入2;否則,分配需要的大小;
2.拷貝要插入點之前的內容
3.構造插入元素順次添加到后面
4.接着把之前插入點后面的內容拷貝到新的空間中
5.釋放原來空間
來看一下GCC的vector擴容過程,大概是,不夠就擴充為原來2倍,擴充為原來2倍還不夠,則擴充至需要大小。
1 int main() 2 { 3 vector<int> vec; 4 for(int i=0; i<20; i++) 5 { 6 cout << "vector size= " << vec.size() << endl; 7 cout << "vector capacity= " << vec.capacity() << endl; 8 //cout << "vector max_size= " << vec.max_size() << endl; 9 vec.push_back(i); 10 } 11 cout << "最后一次, 插入100個元素 " << endl; 12 vec.insert(vec.begin(), 100, 1); 13 cout << "vector size= " << vec.size() << endl; 14 cout << "vector capacity= " << vec.capacity() << endl; 15 //cout << "vector max_size= " << vec.max_size() << endl; 16 17 return 0; 18 }
但是,vector最大空間是固定的。
我用同一段代碼測試vector的最大空間 ,這里有一個疑問,要是超過額定最大空間又會怎么樣?最后有嘗試。
1 int main() 2 { 3 vector<int> vec; 4 for(int i=0; i<20; i++) 5 { 6 cout << "Max_size = " << vec.max_size() << endl; 7 cout << "size = " << vec.size() << endl; 8 vec.push_back(i); 9 cout << "插入 " << i << endl; 10 } 11 return 0; 12 }
(1)GCC 1019
(2)MSVC 109
超出上述max_size后,被系統拒絕insert了,我想那是它的極限了,不能突破。
至此,我們對STL vector的實現就差不多了解了,出去侃侃也足夠了。
代碼來自《STL源碼解析》,源碼迸發着光輝!