基礎(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的所有迭代器就都失效了。這是一般人會犯的錯誤,務必小心。 --侯捷如是說):