STL vector

分析的是sgi STL中vector的版本 http://www.sgi.com/tech/stl/download.html 作爲學習之用
基礎(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的所有迭代器就都失效了。這是一般人會犯的錯誤,務必小心。 --侯捷如是說):


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章