前言
vector 是最常用的 C++ 容器,其动态扩容的特性是普通数组无法具备的,大大增加了编程的灵活性。虽然能基本理解其基本原理,但也无法深层次理解,直到研读了 vector 的源码,才能比较自信的说自己真正理解了 vector 的基本原理,正应了侯捷说的那句话:源码面前,了无密码。我会分两篇文章分别分析泛化 vector 和针对 bool 类型的特化 vector(即是 bit_vector,位vector)。本文将分析泛化的 vector 的源码。
vector概述
vector 是动态扩容的连续数组。普通数组是静态空间,一旦配置就无法改变,而 vector 是动态空间,其内部机制会自动扩充空间以容纳更多的元素。其动态扩容的具体过程是:当容器没有备用空间时,会开辟一块是旧空间两倍大小的新空间,将数据从旧空间复制到新空间并释放原空间。因此,vector 对内存的合理利用和运用的灵活性有很大帮助,我没再也不用考虑数组的容量不足的问题。
vector 源码分析
本文分析的 vector 源码是侯捷老师《STL源码剖析》用的 SGI-STL-v2.91 的版本。其泛化版本的 vector 具体实现在 stl_vector.h 文件中,部分源码如下:
// alloc 是 SGI STL 的空间配置器
template<class T, class Alloc = alloc>
class vector {
public:
typedef T 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;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION //这里是反转迭代器,可先忽略
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#endif
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; }
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_type size() const {
return size_type(end() - begin());
}
size_type max_size() const {
return size_type(-1) / sizeof(T);
}
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);
}
const_reference operator[](size_type n) const {
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(const vector<T, Alloc>& x) {
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
template <class InputIterator>
vector(InputIterator first, InputIterator last) :
start(0), finish(0), end_of_storage(0)
{
range_initialize(first, last, iterator_category(first));
}
~vector() {
destroy(start, finish); //全局变量
deallocate();
}
vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
void reverve(size_type n) {
if (capacity() < n) {
const size_type old_size = size();
iterator tmp = allocate_and_copy(n, start, finish);
destroy(start, finish);
deallocate();
start = tmp;
finish = start + old_size;
end_of_storage = start + n;
}
}
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
void push_back(const T& x) {
if (finish != end_of_storage) { //还有备用空间
construct(finish, x); //全局函数
++finish;
} else //无备用空间
insert_aux(end(), x); //成员函数,后续会分析
}
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);
}
//和push_back差别不大,只是插入位置不一样,复杂一点
iterator insert(iterator position, const T& x) {
size_type n = position - begin();
if (finish != end_of_storage && position == end()) {
construct(finish, x);
} else
insert_aux(position, x);
return begin() + n;
}
iterator insert(iterator position) {
insert(position, T());
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(iterator position, InputIterator first, InputIterator last)
{
range_insert(position, first, last, iterator_category(first));
}
#endif
void insert(iterator pos, size_type n, const T& x);
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);
}
void pop_back() {
--finish;
destroy(finish); //finish->~T 这里仅仅是调用指针finish所指对象的析构函数,不能释放内存
}
iterator erase(iterator position) {
//如果移除的不是最后一个元素
if (position + 1 != end())
copy(position + 1, finish, position); //全局函数
--finish;
destroy(finish);
return position;
}
//移除半开半闭区间[first, last)之间的所有元素,last指向的元素不被移除
iterator erase(iterator first, iterator last) {
iterator i = copy(last, finish, first);
//如果区间内元素的析构函数是trivial的,则什么也不做
//如果区间内元素的析构函数是non-trivial的,则依序调用其析构函数
destroy(i, finish);
finish = finish - (last - first); //重新调整finish
return first;
}
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);
__STL_TRY
{
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
/***********************后续还有********************************/
vector 迭代器
vector 维护的是一个连续空间所以无论其元素的型别为何,普通指针就可以作为 vector 的迭代器而满足所有必要条件,因为 vector 迭代器所需要的操作行为,如 operator*,operator++,operator--,operator+,operator-,operator+=,operator-=,普通指针就具备,从上面的源码就可以看出,vector 用的迭代器就是普通指针。但除 bool 类型,虽然普通指针一样适用,为提高空间利用率,源码为其设计的特化版本有设计专门的迭代器,下一篇文件会进一步探讨。