分析的是sgi STL中vector的版本
http://www.sgi.com/tech/stl/download.html
作为学习之用
SGI STL第一级配置器:
详细介绍insert函数的实现如下图文所示:
基础(SGI STL的空间分配器):
typedef __malloc_alloc_template<0> malloc_alloc;
..
# ifdef __USE_MALLOC
typedef malloc_alloc alloc; //令alloc为第一级配置器
#else
...
// 另外alloc为二级配置器
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
不同的编译器能力不同所以对于预编译项__USE_MALLOC支持,g++默认是二级配置器,当然你也可以通过自己定义__USE_MALLOC来选择是否使用第一级。
对一级或者二级或者其他配置方式进行包装接口
template<class T, class Alloc>
class simple_alloc {
public:
static T *allocate(size_t n)
{ return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
static T *allocate(void)
{ return (T*) Alloc::allocate(sizeof (T)); }
static void deallocate(T *p, size_t n)
{ if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
static void deallocate(T *p)
{ Alloc::deallocate(p, sizeof (T)); }
};
SGI STL第一级配置器:
template <int inst>
class __malloc_alloc_template {...};
其中:
1. allocate()直接调用malloc();
2. deallocate()直接使用的是free();
3. 模拟C++的set_new_handler以处理内存不足的情况 // 见Effective 条款7,operator new(执行分配内存不调用构造函数)使用的就是set_new_handler机制。
template <bool threads, int inst>
class __default_alloc_template {...};
其中:
1. 维护16个自由链表(free list) 8...128bytes的小额区块
如果区块超过128bytes时,移交给第一级配置器处理,当区块小于128bytes时,通过内存池(memory pool)管理(次级配置):每次配置一大块内存,并且维护相应的自由链表(free-lists).如果下次有相同大小的内存需求就直接从这里取;如果释放了内存,则放回到free-lists里面。对于任何的小额内存都会上调到8的倍数。
template <class T, class Alloc = alloc>
class vector {
public:
// 以下Iterator的五种嵌套型别定义,具体设计与作用可以看迭代器(Iterator)概念与traits编程技法
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator; // vector的iterator是原生指针,也就是vector提供的Random Access 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;
/*
例子:客户端vector<int>::iterator it;
那么vector的iterator value_type就是int*; reference_type是int&;
*/
protected:
//simple_alloc见前文SGI STL的空间分配器部分,默认vector就是alloc配置器
typedef simple_alloc<value_type, Alloc> data_allocator; //于是data_allocator::allocate(n)表示的就是分配了n个元素空间
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的类成员函数
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); }
/*
* fill_initialize函数首先会调用allocate配置n个元素空间,
然后调用全局函数uninitialized_fill_n来调用里面元素构造函数
// Vector<int> iv(2,9);这个对象的初始化过程,其中 end_of_storage为n即容量和size一样大
*/
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) {
/*
template <class ForwardIterator>
iterator allocate_and_copy(size_type n,
ForwardIterator first, ForwardIterator last) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_copy(first, last, result);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
*/很清新的看到重新申请了内存,然后调用全局函数uninitialized_copy进行拷贝
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
vector(InputIterator first, InputIterator last) :
start(0), finish(0), end_of_storage(0)
{
range_initialize(first, last, iterator_category(first));
}
#else /* __STL_MEMBER_TEMPLATES */
vector(const_iterator first, const_iterator last) {
size_type n = 0;
distance(first, last, n);
start = allocate_and_copy(n, first, last);
finish = start + n;
end_of_storage = finish;
}
#endif /* __STL_MEMBER_TEMPLATES */
~vector() {
destroy(start, finish);
deallocate();
}
vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
void reserve(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 = tmp + 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); // construct全局函数,直接调用placement new;(元素的内存为finish所指向的内存,同时实现对其元素构造函数的调用)
++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);
}
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()); }
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(iterator position, InputIterator first, InputIterator last) {
range_insert(position, first, last, iterator_category(first));
}
#else /* __STL_MEMBER_TEMPLATES */
void insert(iterator position,
const_iterator first, const_iterator last);
#endif /* __STL_MEMBER_TEMPLATES */
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);
}
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position); //每一次erase需要调用copy导致position后面数据的移动
--finish;
destroy(finish);
return position;
}
iterator erase(iterator first, iterator last) {
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
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()); }
详细介绍insert函数的实现如下图文所示:
如下图4-3b-1所示的情况是,备用空间为2,新增元素也为2,所以,备用空间>=新增元素个数,而插入点之后的元素个数为3大于新增元素个数2(原有元素个数3个+备用空间为2,共5个存储单位)。此种情况的处理方式是,相当于将插入点之后的原有的3个元素整体向后移2个单位,然后把要新增的2个元素从插入点处插入,刚好满足新增的2个元素加上原有的3个元素共同存储在5个单位的空间中。
如下图4-3b-2所示,插入点之后的现有元素个数2<=新增元素个数3,此种情况的处理方式为:相当于将插入点之后的原有的3个元素整体向后移三个单位,然后把新增的3个元素从原插入点处插入:
如果原有空间不够,那么vector将实施所谓的动态增加大小,而动态增加大小,并不是指在原空间之后接连续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间,这点可以从上述insert的实现中的第二部分,当借用空間小于「新增元素個數」(那就必须配置额外的内存)可以看出来。
如下图4-3b-3所示(另外,必须提醒的是,经过上述操作后,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。这是一般人会犯的错误,务必小心。 --侯捷如是说):