顺序容器vector
概述
- vector与array:数据安排和操作方式相似,但array是静态空间,一旦配置了就不能改变,除非用户自己生成空间。vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。
vector的关键在于其对大小的控制以及重新配置时的数据搬移效率。
vector的迭代器
由于vector维护的是一个连续线性空间,所以不论元素类别,普通指针都可以作为vector的迭代器而满足必要条件,包括随机存取、操作符(*、->、++,–,+,-,+=,-=)等操作行为。
vector提供的是random access iterators。
typedef value_type* iterator; //value_type是元素类型
vector容量扩充
线性连续空间,以两个迭代器start
和finish
分别指向配置得来的连续空间中目前已使用的范围,并以迭代器end_of_storage
指向整块连续空间(含备用空间)的尾端。
为了降低空间配置时的速度成本, vector实际配置的大小可能比客户端需求量更大一些,以备将来可能的扩充。
根据vs2017的环境(c++17),若需要空间大于当前capacity的1.5倍,则扩充为需要空间大小,反之扩充为capacity的1.5倍。以下为capacity
增长代码:
size_type _Calculate_growth(const size_type _Newsize) const{
// given _Oldcapacity and _Newsize, calculate geometric growth
const size_type _Oldcapacity = capacity();//vector对应的容量
if (_Oldcapacity > max_size() - _Oldcapacity / 2){
return (_Newsize); // geometric growth would overflow
}
const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2;
if (_Geometric < _Newsize){
return (_Newsize); // geometric growth would be insufficient
}
return (_Geometric); // geometric growth is sufficient
}
vector插入元素
(以下内容参考c++17源码)
push_back
调用emplace_back
template<class... _Valty>
decltype(auto) emplace_back(_Valty&&... _Val){
// insert by perfectly forwarding into element at end, provide strong guarantee
if (_Has_unused_capacity()){
//如果当前capacity足够,则直接插入
_Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
}
else{ // reallocate
const size_type _Oldsize = size();
if (_Oldsize == max_size()) { _Xlength(); }
const size_type _Newsize = _Oldsize + 1;
const size_type _Newcapacity = _Calculate_growth(_Newsize);//需要扩充的容量
bool _Emplaced = false;
const pointer _Newvec = this->_Getal().allocate(_Newcapacity);//分配需要容量的内存
_Alty& _Al = this->_Getal();
//在新内存空间中构造变量
_TRY_BEGIN
_Alty_traits::construct(_Al, _Unfancy(_Newvec + _Oldsize), _STD forward<_Valty>(_Val)...);
_Emplaced = true;
_Umove_if_noexcept(this->_Myfirst(), this->_Mylast(), _Newvec);
_CATCH_ALL
if (_Emplaced){
//若已经覆盖好新的内存,则销毁旧的变量
_Alty_traits::destroy(_Al, _Unfancy(_Newvec + _Oldsize));
}
//销毁旧的内存空间,如果没有覆盖成功,则把新内存空间销毁
_Al.deallocate(_Newvec, _Newcapacity);
_RERAISE;
_CATCH_END
_Change_array(_Newvec, _Newsize, _Newcapacity);
}
#if _HAS_CXX17
return (this->_Mylast()[-1]);
#endif /* _HAS_CXX17 */
}
insert
(插入一个元素)调用emplace
函数
vector源码摘要
(以下内容参考stl源码剖析,和最新版vector(c++17)有所出入)
//alloc 是SGI STL的空间配置器
template <class T, class Alloc = alloc>
class vector{
public:
typedef T value_type;
typedef value_type* pointer;
typedef value_type* iterator; //vector的迭代器是普通指针
typedef value_type& reference;
typedef size_t size_type;
protected:
typedef simple_alloc<value_type, Alloc> data_allocator;
iterator start;// 表示目前使用空间的头
iterator finish;//表示目前使用空间的尾
iterator end_of_storage;//表示目前可用空间的尾
void insert_aux(iterator position, const T& x);
void deallocate(){
if (start)
data_allocator::deallocate(start, end_of_storage - start);
}
void fill_initialize(size_type n, const T& value){
start = allocate_and_fill( n, value );
finish = start + n;
end_of_storage = finish;
}
public:
iterator begin(){ return start; }
iterator end() { return finish; }
size_type size() const { return size_type( end() - begin() ); }
size_type capacity () const{
return size_type(end_of_storage - begin());}
bool empty() const { return begin() == end(); }
reference operator[] (size_type n) { return *(begin()+n); }
vector() : start(0), finish(0), end_of_storage (0) {}
vector( size_type n, const T& value) { fill_initialize( n, value ); }
vector( int n, const T& value ) { fill_initialize(n,value); }
vector(long n, const T& value) { fill_initialize(n, value); }
explicit vector( size_type n) { fill_initialize(n, T() ); }
//explicit 阻止隐式转换,通过T类型的默认初始化函数进行初始化
~vector(){
destroy(start, finish);//全局函数
deallocate();
}
reference front(){ return *begin(); }//第一个元素
reference back(){ return *( end() - 1 ); } // 最后一个元素
void push_back( const T& x){
if (finish != end_of_storage ){
construct( finish, x ); //全局函数
++finish;
}else
insert_aux( end(), x );
}
void pop_back(){
--finish;
destroy( finish ); // 全局函数
}
iterator erase ( iterator position ){
if (position + 1 != end())
copy(position+1, finish, position); // 后续元素往前移动
--finish;
destroy ( finish );
return position;
}
void resize(size_type new_size, const T& x){
if ( new_size < size() )
erase( begin() + new_size, end() );
else
insert(end(), new_size - size(), x);
}
void resize(size_type new_size) { resize( new_size, T() ); }
void clear() { erase( begin(), end() ); }
protected:
iterator allocate_and_fill( size_type n, const T& x ){
iterator result = data_allocator::allocate(n);
uninitialized_fill_n( result, n, x); //全局函数
return result;
}
}