1. vector底層實現機制刨析:
簡述:使用三個迭代器表示的:

這也就解釋了,為什么 vector 容器在進行擴容后,與其相關的指針、引用以及迭代器可能會失效的原因。
insert
整體向后移
erase
整體向前移
size 變化會重新reserve
2. emplace_back()和push_back()的區別
emplace_back() 和 push_back() 的區別,就在于底層實現的機制不同。push_back() 向容器尾部添加元素時,首先會創建這個元素,然后再將這個元素拷貝或者移動到容器中(如果是拷貝的話,事后會自行銷毀先前創建的這個元素);而 emplace_back() 在實現時,則是直接在容器尾部創建這個元素,省去了拷貝或移動元素的過程。
3. 避免不必要的擴容:
那既然擴容會影響程序的運行效率,那我們如何來避免呢?
在插入元素之前,我們可以預估vector里面要存儲多少個元素,我們提前將這個空間給它開辟好就可以了!!!
比如說,我們需要向vector中插入100個元素,在執行push_back之前,我們進行reserver預留空間,只要空間大小給的足夠,在整個插入的過程中就不需要進行任何的擴容!
4. 減小不必要的容量
1 . shrink_to_fit()
2 . Swap
如果想用 swap() 成員方法去除當前 vector 容器多余的容量時,可以套用如下的語法格式:
vector(x).swap(x);
1. #include <iostream>
2. #include <vector>
3. using namespace std;
4.
5. int main()
6. {
7. vector<int>myvector;
8. //手動為 myvector 擴容
9. myvector.reserve(1000);
10. cout << "1、當前 myvector 擁有 " << myvector.size() << " 個元素,容量為 " << myvector.capacity() << endl;
11. //利用 myvector 容器存儲 10 個元素
12. for (int i = 1; i <= 10; i++) {
13. myvector.push_back(i);
14. }
15. //將 myvector 容量縮減至 10
16. vector<int>(myvector).swap(myvector);
17. cout << "2、當前 myvector 擁有 " << myvector.size() << " 個元素,容量為 " << myvector.capacity() << endl;
18. return 0;
19. }
輸出:
1、當前 myvector 擁有 0 個元素,容量為 1000
2、當前 myvector 擁有 10 個元素,容量為 10
顯然,第 16 行代碼成功將 myvector 容器的容量 1000 修改為 10,此行代碼的執行流程可細分為以下 3 步:
- 先執行 vector(myvector),此表達式會調用 vector 模板類中的拷貝構造函數,從而創建出一個臨時的 vector 容器(后續稱其為 tempvector)。
值得一提的是,tempvector 臨時容器并不為空,因為我們將 myvector 作為參數傳遞給了復制構造函數,該函數會將 myvector 容器中的所有元素拷貝一份,并存儲到 tempvector 臨時容器中。
注意,vector 模板類中的拷貝構造函數只會為拷貝的元素分配存儲空間。換句話說,tempvector 臨時容器中沒有空閑的存儲空間,其容量等于存儲元素的個數。 - 然后借助 swap() 成員方法對 tempvector 臨時容器和 myvector 容器進行調換,此過程不僅會交換 2 個容器存儲的元素,還會交換它們的容量。換句話說經過 swap() 操作,myvetor 容器具有了 tempvector 臨時容器存儲的所有元素和容量,同時 tempvector 也具有了原 myvector 容器存儲的所有元素和容量。
- 當整條語句執行結束時,臨時的 tempvector 容器會被銷毀,其占據的存儲空間都會被釋放。注意,這里釋放的其實是原 myvector 容器占用的存儲空間。
經過以上 3 個步驟,就成功的將 myvector 容器的容量由 100 縮減至 10。
當 swap() 成員方法用于清空 vector 容器時,可以套用如下的語法格式:
vector().swap(x);
4. vector < bool >
具體來講,不推薦使用 vector 的原因有以下 2 個:
1. 嚴格意義上講,vector<bool> 并不是一個 STL 容器;
2. vector<bool> 底層存儲的并不是 bool 類型值。
值得一提的是,對于是否為 STL 容器,C++ 標準庫中有明確的判斷條件,其中一個條件是:如果 cont 是包含對象 T 的 STL 容器,且該容器中重載了 [ ] 運算符(即支持 operator[]),則以下代碼必須能夠被編譯:
T *p = &cont[0];
此行代碼的含義是,借助 operator[ ] 獲取一個 cont 容器中存儲的 T 對象,同時將這個對象的地址賦予給一個 T 類型的指針。
這就意味著,如果 vector 是一個 STL 容器,則下面這段代碼是可以通過編譯的:
//創建一個 vector 容器
vectorcont{0,1};
//試圖將指針 p 指向 cont 容器中第一個元素
bool *p = &cont[0];
但不幸的是,此段代碼不能通過編譯。原因在于 vector 底層采用了獨特的存儲機制。
實際上,為了節省空間,vector 底層在存儲各個 bool 類型值時,每個 bool 值都只使用一個比特位(二進制位)來存儲。也就是說在 vector 底層,一個字節可以存儲 8 個 bool 類型值。在這種存儲機制的影響下,operator[ ] 勢必就需要返回一個指向單個比特位的引用,但顯然這樣的引用是不存在的,等號左右兩邊出現沖突!
么,如果在實際場景中需要使用 vector< bool > 這樣的存儲結構,該怎么辦呢?很簡單,可以選擇使用 deque< bool > 或者 bitset 來替代 vector。
要知道,deque 容器幾乎具有 vecotr 容器全部的功能(擁有的成員方法也僅差 reserve() 和 capacity()),而且更重要的是,deque 容器可以正常存儲 bool 類型元素。
還可以考慮用 bitset 代替 vector,其本質是一個模板類,可以看做是一種類似數組的存儲結構。和后者一樣,bitset 只能用來存儲 bool 類型值,且底層存儲機制也采用的是用一個比特位來存儲一個 bool 值。