更多精彩內容,請關注微信公衆號:後端技術小屋c++
stl_vector.h vector.h vector
vector默認使用__default_alloc_template分配內存,該分配器是線程安全的,具體可見STL源碼分析-內存分配後端
vector
是_Vector_base
的派生類,_Vector_base
有三個成員變量api
protected: _Tp* _M_start; _Tp* _M_finish; _Tp* _M_end_of_storage;
咱們都知道,vector是一種更高級的數組,而數組必然包含一段連續的緩衝區。以下所示,_M_start
表示這段緩衝區內數據區的左實邊界,_M_finish
表示緩衝區內數據區的右虛邊界,_M_end_of_storage
指向內存緩衝區的右虛邊界
數組
vector使用連續的物理內存空間,所以迭代器直接使用原始指針表示安全
typedef _Tp value_type; typedef value_type* iterator; // vector的迭代器是普通指針 typedef const value_type* const_iterator; typedef reverse_iterator<const_iterator> const_reverse_iterator; typedef reverse_iterator<iterator> reverse_iterator;
reverse_iterator
的定義在stl_iterator.h
中,反向迭代器實際上是對正向迭代器的一層封裝。微信
例如vector<int> a
; 這種狀況下,vector
大小爲零,爲了節約內存空間,vector<int>
不會主動申請內存、建立緩衝區。函數
explicit vector(const allocator_type& __a = allocator_type()) : _Base(__a) {} _Vector_base(const _Alloc&) : _M_start(0), _M_finish(0), _M_end_of_storage(0) {}
例如vector<int> a(100, 0)
,這種狀況下,_Vector_base
首先使用_Alloc
類型的內存分配器分配n*sizeof(Tp)
的內存,而後在Vector
構造函數中填充初始值源碼分析
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()); } _Vector_base(size_t __n, const _Alloc&) : _M_start(0), _M_finish(0), _M_end_of_storage(0) { _M_start = _M_allocate(__n); _M_finish = _M_start; _M_end_of_storage = _M_start + __n; }
例如佈局
vector<int> a(100, 0); vector<int> b(a); // 複製構造函數
_Vector_base
首先使用_Alloc
類型的分配器分配n*sizeof(Tp)
的內存,而後Vector
構造函數將__x
的值複製到本地緩衝區中。線程
vector(const vector<_Tp, _Alloc>& __x) : _Base(__x.size(), __x.get_allocator()) { _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }
例如
vector<int> a(100, 0); vector<int> b(a.begin(), a.begin() + 10);
注意這裏_Vector_base
並無提早申請長度爲last-first的內存,而是在vector::_M_range_initialize
中調用_M_allocate
來申請內存的。
TODO 注意,這裏須要區分_InputIterator
是否爲整數類型
// Check whether it's an integral type. If so, it's not an iterator. 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()); } template <class _Integer> void _M_initialize_aux(_Integer __n, _Integer __value, __true_type) { _M_start = _M_allocate(__n); _M_end_of_storage = _M_start + __n; _M_finish = uninitialized_fill_n(_M_start, __n, __value); }
例如vector<int> a(100, 0);
當a
被回收時,首先調用vector::~vector
將包含的全部元素回收,而後調用_Vector_base::~_Vector_base
釋放已申請的內存。
~vector() { destroy(_M_start, _M_finish); } ~_Vector_base() { _M_deallocate(_M_start, _M_end_of_storage - _M_start); }
分兩種狀況,
inplacement new
realloc
生成新緩衝區, 將舊緩衝區上的數據複製到新緩衝區代碼細節:
首先判斷是否有空閒內存,若是有,則在空閒內存上執行inplacement new
void push_back(const _Tp& __x) { if (_M_finish != _M_end_of_storage) { construct(_M_finish, __x); ++_M_finish; } else _M_insert_aux(end(), __x); } template <class _T1, class _T2> inline void _Construct(_T1* __p, const _T2& __value) { new ((void*) __p) _T1(__value); }
若是沒有空閒內存,則執行_M_insert_aux
,接着進入else分支,能夠看到,若是push_back
以前capacity
爲0, 擴展後的capacity
爲1,不然新capacity
是舊capacity
的兩倍。
template <class _Tp, class _Alloc> void vector<_Tp, _Alloc>::_M_insert_aux(iterator __position) { if (_M_finish != _M_end_of_storage) { construct(_M_finish, *(_M_finish - 1)); ++_M_finish; copy_backward(__position, _M_finish - 2, _M_finish - 1); *__position = _Tp(); } 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); ++__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; } }
內存分配的調用鏈路爲
_M_allocate -> simple_alloc<_Tp, _Alloc>::allocate -> _Alloc::allocate (_Alloc默認爲__STL_DEFAULT_ALLOCATOR(_Tp)) -> allocator<_Tp> -> __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0>
而__default_alloc_template
的實現細節見STL源碼分析-內存分配
_M_start
, _M_finish
, _M_end_of_storage
這三個指針便可push_back
, 不一樣點在於insert須要移動插入位置以後的全部元素new_size - old_size
個0值old_size - new_size
個元素執行erase
,須要注意的是,resize並不會釋放緩衝區上可用內存a.swap(tmp)
operator=
operator=
推薦閱讀
更多精彩內容,請掃碼關注微信公衆號:後端技術小屋。若是以爲文章對你有幫助的話,請多多分享、轉發、在看。