先来一张侯捷书上的图吧
容器的衍生并不是通过继承,而是通过组合。比如:stack和queue里包含一个deque,set和map里包含一个rb-tree或hash_table。
vector
vector有点类似array,但vector是可以扩展的,但vector在扩展时,需要经历以下三个步骤:配置新空间=》移动数据=》释放旧空间,因此,如果vector空间配置策略不佳,则可能造成较大的空间成本损失。
vector定义摘要
实现在<stl_vector.h>先看看类型定义吧
// SGI默认的是alloc配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector : protected _Vector_base<_Tp, _Alloc>
{
__STL_CLASS_REQUIRES(_Tp, _Assignable);
private:
typedef _Vector_base<_Tp, _Alloc> _Base;
public:
typedef _Tp value_type; // 元素类型
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator; // 迭代器类型,这里是原生指针
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type; // 容量大小
typedef ptrdiff_t difference_type; // 区间范围类型
typedef typename _Base::allocator_type allocator_type; // 空间分配器类型
// 从父类vector_base继承下来的,_TP* 就是 iterator
_Tp* _M_start; // 空间头部
_Tp* _M_finish; // 空间尾部
_Tp* _M_end_of_storage; // 目前空间可用的尾
...
};
所以,vector<Shape>::iterator iv 这样申明迭代器,其实迭代器其就是Shape类型
vector数据结构
其他比较关键点的函数
在某一个位置进行插入一个值:insert_aux()
template <class _Tp, class _Alloc>
void
vector<_Tp, _Alloc>::_M_insert_aux(iterator __position)
{
// 如果还有备用空间
if (_M_finish != _M_end_of_storage) {
// 这里我不是很明白,finish位置的元素通过construct初始化,
// 再将[position,finish-2]的元素往后拷贝,为新元素腾出位置
// 直接将[position,finish-1]的元素往后拷贝不就行了?
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;
// 旧的vector拷贝到新的中去
__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);
}
// 析构旧的vector,调整新的vector的迭代器
__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;
}
}
在一个位置插入一段区间的代码类型,不赘述了。
删除一段区间的元素 erase()
iterator erase(iterator __first, iterator __last) {
// 把区间后面的元素往前移动 last-first个位置
iterator __i = copy(__last, _M_finish, __first);
// 把[i.last)部分析构掉,如区间长度为4,区间后面只有3个元素
destroy(__i, _M_finish);
_M_finish = _M_finish - (__last - __first);
return __first;
}
同样erase()也有只删除一个值的版本,这里也不赘述了