源代码来自sgi-2.91版本stl_vector.h
文章目录
vector总览图
当capacity空间不足时,新分配一个两倍空间,把所有数据做拷贝操作。
start是数据头部
finish是数据尾部下一位
capacity是实际的容器空间尾部
vector类
template <class T, class Alloc = alloc> //默认分配器为alloc,其原理是内存池机制
class vector {
public:
typedef T value_type; //value_type为数据类型
/*以下是一些名称定义*/
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator; //可以看出vector的迭代器就是指向数据类型的指针
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; //数据间距,经由萃取器,提供给算法的信息
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator; //反转迭代器
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_iterator<const_iterator, value_type, const_reference,
difference_type> const_reverse_iterator;
typedef reverse_iterator<iterator, value_type, reference, difference_type>
reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
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) { //填充n个值为value的数,数据类型为T
start = allocate_and_fill(n, value); //见下
finish = start + n;
end_of_storage = finish;
}
allocate_and_fill函数
iterator allocate_and_fill(size_type n, const T& x) {
iterator result = data_allocator::allocate(n); //分配内存空间,此处n太大,会交给一级分配器开辟空间
__STL_TRY {
uninitialized_fill_n(result, n, x); //在result指向的内存空间填充n个x
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
allocate_and_copy函数
iterator allocate_and_copy(size_type n,
const_iterator first, const_iterator last) {
//n代表拷贝个数,first代表拷贝起点,last是拷贝终点
iterator result = data_allocator::allocate(n); //新分配一快空间,足够放n块数据
__STL_TRY {
uninitialized_copy(first, last, result); //系统函数拷贝,把first到last区间的数据拷贝到result指向的内存块
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
vector构造函数分析
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_initialize(n, value); } //填充n个value值
vector(int n, const T& value) { fill_initialize(n, value); } //填充n个value值
vector(long n, const T& value) { fill_initialize(n, value); } //填充n个value值
explicit vector(size_type n) { fill_initialize(n, T()); } //填充n个默认值值
vector(const vector<T, Alloc>& x) { //拷贝另一个vector值
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
vector(const_iterator first, const_iterator last) { //区间构造
size_type n = 0;
distance(first, last, n); //算法根据迭代器类型(经由triats)算出需要的数据个数n
start = allocate_and_copy(n, first, last); //分配空间并拷贝
finish = start + n;
end_of_storage = finish;
}
析构函数
~vector() {
destroy(start, finish); //调用区间的析构函数
deallocate(); //回收内存
}
reserve函数分析
void reserve(size_type n) { //扩充容器空间
if (capacity() < n) {
const size_type old_size = size();
iterator tmp = allocate_and_copy(n, start, finish); //分配n个数据个数的空间并拷贝旧数据
destroy(start, finish); //旧数据全部调用析构函数
deallocate(); //回收旧空间
start = tmp;
finish = tmp + old_size;
end_of_storage = start + n; //更新指针地址信息
}
}
数据位置函数 front()、back()
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
迭代器相关函数分析:begin()、end()
iterator begin() { return start; } //返回数据的头部指针
const_iterator begin() const { return start; }
iterator end() { return finish; } //返回数据的尾部指针,实际是尾部数据的下一位
const_iterator end() const { return finish; }
reverse_iterator rbegin() { return reverse_iterator(end()); } //反向迭代器,实际返回尾部
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); } //反向迭代器,实际返回头部
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
容器大小函数 size() 、 capacity()
size_type size() const { return size_type(end() - begin()); } //头尾迭代器相减
size_type max_size() const { return size_type(-1) / sizeof(T); } //vector<int> 测试是1073741823(vs2019)
size_type capacity() const { return size_type(end_of_storage - begin()); }//实际容器内存空间大小
bool empty() const { return begin() == end(); } //判断是否有数据
operator[]运算符重载
reference operator[](size_type n) { return *(begin() + n); } //迭代器移动来实现
const_reference operator[](size_type n) const { return *(begin() + n); }
operator=运算符重载
vector<T, Alloc>& operator=(const vector<T, Alloc>& x); //类中定义
template <class T, class Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator=(const vector<T, Alloc>& x) {
if (&x != this) { //标准询问,是否等于自身
if (x.size() > capacity()) { //空间不够存放数据
iterator tmp = allocate_and_copy(x.end() - x.begin(),
x.begin(), x.end());
//拷贝函数,tmp指向的区域已经存放好拷贝的数据
destroy(start, finish); //调用这个区间所有对象的析构函数
deallocate(); //如果由一级分配器负责,则销毁这片区域,如果是二级分配器,则只是回收这片区域
start = tmp; //更新头部地址
end_of_storage = start + (x.end() - x.begin()); //更新容器尾部地址
}
else if (size() >= x.size()) { //空间足够的话,不用新建空间就可以拷贝数据
iterator i = copy(x.begin(), x.end(), begin()); //i返回新数据区间的尾部地址
destroy(i, finish); //析构原先vector中剩余的数据
}
else { //新数据个数比旧的多,但是总容器空间仍足够存放数据
copy(x.begin(), x.begin() + size(), start); //先覆盖原先数据
uninitialized_copy(x.begin() + size(), x.end(), finish); //接着上面的尾部继续复制
}
finish = start + x.size(); //更新尾部指针
}
return *this;
}
operator==运算符重载
template <class T, class Alloc>
inline bool operator==(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
//equal函数可以逐个比较容器间元素是否相同
}
operator<运算符重载
template <class T, class Alloc>
inline bool operator<(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
//lexicographical_compare字典序比较两个序列
insert_aux函数
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
if (finish != end_of_storage) {
construct(finish, *(finish - 1)); //finish地址处拷贝构造前一个数
++finish; //尾部指针移动
T x_copy = x;
copy_backward(position, finish - 2, finish - 1); //区间数据复制拷贝到finish-1之前,详见下面图片分析
*position = x_copy; //在这个位置插入x
}
else { //如果没有空间的话,需要新分配空间
const size_type old_size = size();
const size_type len = old_size != 0 ? 2 * old_size : 1; //2倍扩展空间
iterator new_start = data_allocator::allocate(len); //开辟len大小内存空间
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start); //先把position之前区间的旧数据拷贝。
construct(new_finish, x); //此时new_finish=position,在此处插入数据x
++new_finish;
new_finish = uninitialized_copy(position, finish, new_finish); //拷贝之后区间的值,new_finish 此时是数据尾部
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) { //处理异常
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(begin(), end()); //调用原来旧数据的析构函数
deallocate(); //回收空间
start = new_start;
finish = new_finish; //更新数据头尾地址指针
end_of_storage = new_start + len; //更新容器尾部地址
}
}
copy_backward() 系统函数
copy_backward() 会复制前两个迭代器参数指定的序列。第三个参数是目的序列的结束迭代器,通过将源序列中的最后一个元素复制到目的序列的结束迭代器之前,源序列会被复制到目的序列中,如图 1 所示。copy_backward() 的 3 个参数都必须是可以自增或自减的双向迭代器,这意味着这个算法只能应用到序列容器的序列上。 如图:
push_back函数
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x); //在finish位置执行x的构造函数
++finish;
}
else
insert_aux(end(), x); //没有空间了,需要扩充空间
}
insert函数
iterator insert(iterator position, const T& x) { //指定位置插入数据
size_type n = position - begin();
if (finish != end_of_storage && position == end()) { //尾部插入
construct(finish, x);
++finish;
}
else
insert_aux(position, x); //空间不足或在中间位置插入
return begin() + n;
}
iterator insert(iterator position) { return insert(position, T()); } //调用上面函数,参数为T的默认构造
void insert (iterator pos, int n, const T& x) {
insert(pos, (size_type) n, x);
}
void insert (iterator pos, long n, const T& x) {
insert(pos, (size_type) n, x);
}
下面这个版本指定位置插入n个数据
template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, size_type n, const T& x) {
if (n != 0) {
if (size_type(end_of_storage - finish) >= n) { //剩余空间足够
T x_copy = x;
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n) { //插入位置到数据尾部之间够放n个数
uninitialized_copy(finish - n, finish, finish); //把数据尾部之前n个数据拷贝到尾部之后,腾出n个数据的空间
finish += n; //更新尾部位置
copy_backward(position, old_finish - n, old_finish); //拷贝区间数据(position, old_finish - n)到old_finish之前
//这里感觉一个copy_backward就可以完成,不懂为什么分两步
fill(position, position + n, x_copy); //填充数据
}
else { //插入位置到数据尾部之间不够放n个数
uninitialized_fill_n(finish, n - elems_after, x_copy); //数据尾部填充不够的差数
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish); //把旧数据拷贝到新位置
finish += elems_after;
fill(position, old_finish, x_copy); //填充剩下的x
}
}
else { //容器空间不足,需要扩容
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
iterator new_start = data_allocator::allocate(len); //新分配内存空间
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start); //拷贝position之前旧区间数据到新空间
new_finish = uninitialized_fill_n(new_finish, n, x); //填充n个x
new_finish = uninitialized_copy(position, finish, new_finish); //拷贝position之后旧区间数据到新空间
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish); //调用之前空间数据的析构函数
deallocate(); //回收内存
start = new_start;
finish = new_finish;
end_of_storage = new_start + len; //更新地址指针
}
}
}
pop_back函数
void pop_back() {
--finish;
destroy(finish);
}
swap函数
void swap(vector<T, Alloc>& x) {
__STD::swap(start, x.start);
__STD::swap(finish, x.finish);
__STD::swap(end_of_storage, x.end_of_storage);
}
erase函数
iterator erase(iterator position) { //指定位置删除
if (position + 1 != end()) //如果此位置后面有数据的话
copy(position + 1, finish, position); //把后面所有数据(position + 1到finish之间)全部拷贝到positon位置后,实际全部前移一位
--finish; //更新尾部指针
destroy(finish); //此处数据复制到前一位了,多余
return position;
}
iterator erase(iterator first, iterator last) { //区间数据删除
iterator i = copy(last, finish, first); //把last后面的数据移到前面来,i是新的数据尾部
destroy(i, finish); //多余数据调用析构函数
finish = finish - (last - first); //更新尾部
return first;
}
resize函数
//扩充或者删除数据到指定数量
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()); } //同上
clear函数
void clear() { erase(begin(), end()); }