更多精彩内容,请关注微信公众号:后端技术小屋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=
推荐阅读
更多精彩内容,请扫码关注微信公众号:后端技术小屋。若是以为文章对你有帮助的话,请多多分享、转发、在看。