本文大部分内容转载于:https://blog.csdn.net/qq_41453285/article/details/103565158,他的具体内容也是把stl源码剖析进行了重点的摘要。
1.vector概述
vector的数据安排以及操作方式与array非常类似。两者唯一的差别就是在于空间的运用灵活性,array是静态空间,一旦分配了就是固定的,无法改变其大小。需要用户重新申请更大的空间,移动数据,释放原来的空间。而vector是动态空间,有其内部的空间分配机制来及时调整空间大小,其实就是vector把申请空间,移动数据,释放原来的空间等操作封装在内部,不需要用户去处理。
//alloc是SGI STL的空间配置器
template <class T, class Alloc = alloc>
class vector {
public:
// vector 的嵌套类型定义
typedef T value_type;
typedef value_type* pointer;
typedef value_type* iterator;
typedef value_type& reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
// simple_alloc是SGI STL的空间配置器,见前面空间适配器文章的介绍
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()); }
~vector()
destroy(start, finish); //全局函式,见前面文章destroy函数的介绍
deallocate(); //这是 vector的㆒个 member function
}
reference front() { return *begin(); } // 第一个元素
reference back() { return *(end() - 1); } // 最后一个元素
void push_back(const T& x) { // 将元素安插至最尾端
if (finish != end_of_storage) {
construct(finish, x); //全局函式,见前面文章construct函数的介绍
++finish;
}
else
insert_aux(end(), x); //这是 vector的一个member function
}
void pop_back() { // 将最尾端元素取出
--finish;
destroy(finish); // 全局函式,见前面文章destroy函数的介绍
}
iterator erase(iterator position) { // 清除某位置上的元素
if (position + 1 != end())
copy(position + 1, finish, position); // 后续元素往前搬移
--finish;
destroy(finish); // 全局函式,见前面文章destroy函数的介绍
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); // 全局函式,见前面uninitialized_fill_n函数的介绍
return result;
}
vector的迭代器
vector内部只有四个成员变量,三个迭代器和1个空间配置器。
vector维护的是一个连续的线性空间,所以不论其元素类型是什么,普通指针都可以作为vector的迭代器并且满足迭代器的所有必要条件。
实际上,vector的迭代器就是原生指针,只不过换了个名字。在x86系统下,sizeof(vector<int>) 的结果为32。
// vector 的嵌套类型定义
typedef T value_type; //类型
typedef value_type* pointer; //指针
typedef value_type* iterator; //迭代器
vector存储数据的空间是线性连续的,因此支持随机的下标访问。
typedef simple_alloc<value_type, Alloc> data_allocator;
iterator start; // 表示目前使用空间的头
iterator finish; // 表示目前使用空间的尾
iterator end_of_storage; // 表示目前可用空间的尾
运用start、finish、end_of_storage三个迭代器,vector提供了首尾标示、大小、容量、空容器判断、注标[]运算符、最前端元素值、最后端元素值…等机能,如下
template <class T, class Alloc = alloc>
class vector {
...
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); }
reference front() { return *begin(); }
reference back() { return *(end() - 1); }
...
};
vector的构造与内存管理
vector默认使用alloc做为空间配置器,并据此另外定义了一个data_allocator,为的是更方便以元素大小为配置单位:
template <class T, class Alloc = alloc>
class vector {
protected:
// simple_alloc<>见前面文章介绍
typedef simple_alloc<value_type, Alloc> data_allocator;
...
};
于是,data_allocator::allocate(n) 表示配置n个元素空间
vector的内存动态增长:当插入新元素时,空间已经不够用的时候,会申请一个新的空间,新空间的大小为当前空间大小的1.5倍(有些地方设置的是2倍),然后将原来的元素逐个拷贝到新空间里,释放原来的空间,插入新元素。
即 1、2、3、4、6、9…依次增长。在删除元素的时候并不会动态的调整空间的大小
vector内部空间变化:由于vector维护的空间是线性的连续的,因此也就引入一个新的问题,当在某个地方插入或删除新的元素的时候,会导致后面的元素需要逐个后移或前移,让出足够空间来插入这个新元素或者后面的元素前移来覆盖掉要删除的元素。
这些内部的空间变化都会导致相应的迭代器失效,即原先迭代器指向的数据发生了变化,需要注意。
vector的构造函数:
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()); }
常用的操作:
//数据量
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); }
// 第一个元素
reference front() { return *begin(); }
// 最后一个元素
reference back() { return *(end() - 1); }
// 将元素安插至最尾端
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x); //全局函式,见前面文章construct函数的介绍
++finish;
}
else
insert_aux(end(), x); //这是 vector的一个member function
}
// 将最尾端元素取出
void pop_back() {
--finish;
destroy(finish); // 全局函式,见前面文章destroy函数的介绍
}
// 清除某位置上的元素
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position); // 后续元素往前搬移
--finish;
destroy(finish); // 全局函式,见前面文章destroy函数的介绍
return position;
}
//重新分配vector大小为n个指定的值
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);
}
//重新分配vector大小为n个默认的值
void resize(size_type new_size) { resize(new_size, T()); }
//清空vector
void clear() { erase(begin(), end()); }
insert函数的源代码
//从position开始,插入n个元素,元素初值为x
template<class T,class Alloc>
void vector<T, Alloc>::insert(iterator position, size_type n, const T& x)
{
if (n != 0) { //当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){
//“插入点之后的现有元素个数”大于“新增元素个数”
uninitialized_copy(finish - n, finish, finish);
finish += n; // 将vector尾端标记后移
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy); //从插入点开始填入新值
}
}
else {
//“插入点之后的现有元素个数”小于等于“新增元素个数”
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);
}
}
else {
// 备用空间小于“新增元素个数”(那就必须配置额外的内存)
// 首先决定新长度:旧长度的两倍,或旧长度+新增元素个数
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
// 以下配置新的vector空间
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
STL_TRY {
// 以下首先将旧vector的安插点之前的元素复制到新空间
new_finish = uninitialized_copy(start, position, new_start);
// 以下再将新增元素(初值皆为n)填入新空间
new_finish = uninitialized_fill_n(new_finish, n, x);
// 以下再将旧 vector 的插入点之后的元素复制到新空间
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef STL_USE_EXCEPTIONS
catch(...) {
// 如有异常发生,实现"commit or rollback" semantics.
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* STL_USE_EXCEPTIONS */
// 以下清除并释放旧的vector
destroy(start, finish);
deallocate();
// 以下调整水位标记
start = new_start; finish =
new_finish; end_of_storage =
new_start + len;
}
}