STL容器之vector源碼詳細解讀
簡介
vector的數據安排和array和類似,它們的主要差別在于空間的運用和靈活性,array是靜態(tài)空間,一旦配置了就不能改變
vector是動態(tài)空間,隨著元素的加入,它會自動擴充空間以容納新的元素。
構造函數
// 默認構造函數 explicit vector(const allocator_type& __a = allocator_type()) : _Base(__a) {} // 構造擁有 n 個有值 value 的元素的容器 vector(size_type __n, const _Tp& __value, const allocator_type& __a = allocator_type()) : _Base(__n, __a) { _M_finish = uninitialized_fill_n(_M_start, __n, __value); } explicit vector(size_type __n) : _Base(__n, allocator_type()) { _M_finish = uninitialized_fill_n(_M_start, __n, _Tp()); } // 拷貝構造,構造擁有 __x 內容的容器 vector(const vector<_Tp, _Alloc>& __x) : _Base(__x.size(), __x.get_allocator()) { _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); } // 構造擁有范圍 [first, last) 內容的容器 template <class _InputIterator> vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) { typedef typename _Is_integer<_InputIterator>::_Integral _Integral; _M_initialize_aux(__first, __last, _Integral()); } // 構造擁有范圍 [first, last) 內容的容器 vector(const _Tp* __first, const _Tp* __last, const allocator_type& __a = allocator_type()) : _Base(__last - __first, __a) { _M_finish = uninitialized_copy(__first, __last, _M_start);
主要函數
vector中主要有以下幾個內部變量:
_Tp* _M_start; // 表示目前使用空間的頭 _Tp* _M_finish; // 表示目前使用空間的尾 _Tp* _M_end_of_storage; // 表示目前可用空間的尾
其在內存中的示意圖如下所示:
我們下面主要看vector添加元素的push_back函數。
push_back
push_back的源代碼如下所示:
// 尾部插入 void push_back(const _Tp& __x) { if (_M_finish != _M_end_of_storage) { // 有備用空間 construct(_M_finish, __x); // 全局函數,將 __x 設定到 _M_finish 指針所指的空間上 ++_M_finish; // 調整 } else _M_insert_aux(end(), __x); // 無備用空間,重新分配再插入 } template <class _Tp, class _Alloc> void vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x) { if (_M_finish != _M_end_of_storage) { // 有備用空間 construct(_M_finish, *(_M_finish - 1)); ++_M_finish; _Tp __x_copy = __x; copy_backward(__position, _M_finish - 2, _M_finish - 1); *__position = __x_copy; } else { // 沒有備用空間 const size_type __old_size = size(); const size_type __len = __old_size != 0 ? 2 * __old_size : 1; iterator __new_start = _M_allocate(__len); iterator __new_finish = __new_start; __STL_TRY { __new_finish = uninitialized_copy(_M_start, __position, __new_start); construct(__new_finish, __x); ++__new_finish; __new_finish = uninitialized_copy(__position, _M_finish, __new_finish); } __STL_UNWIND((destroy(__new_start,__new_finish), _M_deallocate(__new_start,__len))); destroy(begin(), end()); _M_deallocate(_M_start, _M_end_of_storage - _M_start); _M_start = __new_start; _M_finish = __new_finish; _M_end_of_storage = __new_start + __len; } }
vector插入元素的主要步驟為:
1、判斷備用空間是否已經用完;
2、若未用完,則直接在備用空間上插入元素,并更新元素尾指針;
3、若已經用完,則重新分配內存,并將舊元素復制到新的地址空間,然后插入新元素。
其中,vector對于空間的增長方式為:
const size_type __len = __old_size != 0 ? 2 * __old_size : 1;
即初始時,vector的空間為1,后續(xù)每次都會以舊空間的2倍增長。
clear
void clear() { erase(begin(), end()); } // 清除 [first, last) 中的所有元素 iterator erase(iterator __first, iterator __last) { iterator __i = copy(__last, _M_finish, __first); destroy(__i, _M_finish); _M_finish = _M_finish - (__last - __first); return __first; }
clear是通過調用erase函數來完成的,其中,在清除元素時,erase函數會將未被清除的元素拷貝的vector頭部,然后依次釋放后面的空間,我們不再過多贅述。
特點
1、vector使用的是內存中連續(xù)的地址空間,如果已分配的內存空間不夠使用時,則vector會以舊容量的2倍來進行擴充,這些都是vector內部來完成的,不需要我們去控制;
2、vector具有隨機訪問的能力,訪問節(jié)點的效率很高,vector對[]的重載函數為
reference operator[](size_type __n) { return *(begin() + __n); } // 重載 [],訪問指定的元素 iterator begin() { return _M_start; } // 返回指向容器第一個元素的迭代器
其中,_M_start為原生指針,原生指針屬于Random access iterator,所以,vector具備了隨機訪問元素的能力。
到此這篇關于STL容器之vector源碼詳細解讀的文章就介紹到這了,更多相關vector源碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C/C++ 運用Npcap發(fā)送UDP數據包的完美過程
UDP 是一種無連接、輕量級的傳輸層協議,與 TCP 相比,它不提供可靠性、流控制和錯誤恢復機制,但卻更加簡單且具有較低的開銷,這篇文章主要介紹了C/C++ 運用Npcap發(fā)送UDP數據包,需要的朋友可以參考下2023-11-11C++中Digraphs、Trigraphs和Tokens的深入講解
這篇文章主要給大家介紹了關于C++中Digraphs、Trigraphs和Tokens的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用C++具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-09-09