STL容器之vector源碼詳細解讀
簡介
vector的數(shù)據(jù)安排和array和類似,它們的主要差別在于空間的運用和靈活性,array是靜態(tài)空間,一旦配置了就不能改變
vector是動態(tài)空間,隨著元素的加入,它會自動擴充空間以容納新的元素。
構(gòu)造函數(shù)
// 默認構(gòu)造函數(shù) explicit vector(const allocator_type& __a = allocator_type()) : _Base(__a) {} // 構(gòu)造擁有 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()); } // 拷貝構(gòu)造,構(gòu)造擁有 __x 內(nèi)容的容器 vector(const vector<_Tp, _Alloc>& __x) : _Base(__x.size(), __x.get_allocator()) { _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); } // 構(gòu)造擁有范圍 [first, last) 內(nèi)容的容器 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()); } // 構(gòu)造擁有范圍 [first, last) 內(nèi)容的容器 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);
主要函數(shù)
vector中主要有以下幾個內(nèi)部變量:
_Tp* _M_start; // 表示目前使用空間的頭 _Tp* _M_finish; // 表示目前使用空間的尾 _Tp* _M_end_of_storage; // 表示目前可用空間的尾
其在內(nèi)存中的示意圖如下所示:
我們下面主要看vector添加元素的push_back函數(shù)。
push_back
push_back的源代碼如下所示:
// 尾部插入 void push_back(const _Tp& __x) { if (_M_finish != _M_end_of_storage) { // 有備用空間 construct(_M_finish, __x); // 全局函數(shù),將 __x 設(shè)定到 _M_finish 指針所指的空間上 ++_M_finish; // 調(diào)整 } 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、判斷備用空間是否已經(jīng)用完;
2、若未用完,則直接在備用空間上插入元素,并更新元素尾指針;
3、若已經(jīng)用完,則重新分配內(nèi)存,并將舊元素復(fù)制到新的地址空間,然后插入新元素。
其中,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是通過調(diào)用erase函數(shù)來完成的,其中,在清除元素時,erase函數(shù)會將未被清除的元素拷貝的vector頭部,然后依次釋放后面的空間,我們不再過多贅述。
特點
1、vector使用的是內(nèi)存中連續(xù)的地址空間,如果已分配的內(nèi)存空間不夠使用時,則vector會以舊容量的2倍來進行擴充,這些都是vector內(nèi)部來完成的,不需要我們?nèi)タ刂疲?/p>
2、vector具有隨機訪問的能力,訪問節(jié)點的效率很高,vector對[]的重載函數(shù)為
reference operator[](size_type __n) { return *(begin() + __n); } // 重載 [],訪問指定的元素 iterator begin() { return _M_start; } // 返回指向容器第一個元素的迭代器
其中,_M_start為原生指針,原生指針屬于Random access iterator,所以,vector具備了隨機訪問元素的能力。
到此這篇關(guān)于STL容器之vector源碼詳細解讀的文章就介紹到這了,更多相關(guān)vector源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言實現(xiàn)輸出鏈表中倒數(shù)第k個節(jié)點
這篇文章主要介紹了C語言實現(xiàn)輸出鏈表中倒數(shù)第k個節(jié)點,主要涉及鏈表的遍歷操作,是數(shù)據(jù)結(jié)構(gòu)中鏈表的常見操作。需要的朋友可以參考下2014-09-09C/C++ 運用Npcap發(fā)送UDP數(shù)據(jù)包的完美過程
UDP 是一種無連接、輕量級的傳輸層協(xié)議,與 TCP 相比,它不提供可靠性、流控制和錯誤恢復(fù)機制,但卻更加簡單且具有較低的開銷,這篇文章主要介紹了C/C++ 運用Npcap發(fā)送UDP數(shù)據(jù)包,需要的朋友可以參考下2023-11-11Qt 數(shù)據(jù)庫QSqlDatabase使用示例
本文主要介紹了Qt數(shù)據(jù)庫QSqlDatabase使用示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12C++中Digraphs、Trigraphs和Tokens的深入講解
這篇文章主要給大家介紹了關(guān)于C++中Digraphs、Trigraphs和Tokens的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09