vector容器的動態分配空間

vector容器的底層實現基於數組,裏面封裝了大量高效的方法,可以完美取代掉數組。整個容器的核心實際上就是動態分配內存,也是其性能優於數組的重要原因。下面重點解析它的核心函數push_back函數:

當數組中增加一個元素x的時候,先判斷是否還有備用空間;如果還有備用空間,則將當前指針的值設爲x,並將當前的指針加1;若備用空間已經用完,如果之前的空間爲0,則重新分配大小爲1的空間,否則將空間擴容爲之前的兩倍,然後將舊容器中的值重新拷貝到新空間中,並重新分配起始指針和當前指針。所以使用vector需要注意的一點就是儘量不要動態給它分配空間。而且空間重新分配之後,之前的所有指針都會失效(特別要注意)

具體實現:

void push_back(const T& x) {
    if (finish != end_of_storage) { //若當前還有備用空間
      construct(finish, x); //將當前水位的值設爲x
      ++finish; //提升水位
    }
    else
      insert_aux(end(), x); 
}
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
  if (finish != end_of_storage) {
    construct(finish, *(finish - 1));
    ++finish;
    T x_copy = x;
    copy_backward(position, finish - 2, finish - 1);
    *position = x_copy;
  }
  else {
    const size_type old_size = size(); //獲取之前數組的大小
    const size_type len = old_size != 0 ? 2 * old_size : 1; //將當前數組的容量擴大爲原來的兩倍
    iterator new_start = data_allocator::allocate(len); //重新分配新數組的起始迭代器
    iterator new_finish = new_start;
    __STL_TRY {
      new_finish = uninitialized_copy(start, position, new_start); //將舊數組的值重新分配給當前的新數組
      construct(new_finish, x); //將當前數組的水位的值設爲x
      ++new_finish; //提升新數組的水位
      new_finish = uninitialized_copy(position, finish, new_finish); //這語句感覺可有可無,因爲它根本就不會執行,position即last,而finish也是last
    }

#       ifdef  __STL_USE_EXCEPTIONS 
    catch(...) { //如果重新構造的新數組出現異常,則銷燬當前新創建的數組,並釋放內存空間
      destroy(new_start, new_finish); 
      data_allocator::deallocate(new_start, len);
      throw;
    }
#       endif /* __STL_USE_EXCEPTIONS */
    destroy(begin(), end()); //將舊數組的空間釋放掉
    deallocate();
    start = new_start; //new_start記錄新數組的起始位置
    finish = new_finish; //重新設置當前水位的指針
    end_of_storage = new_start + len; //設置新數組的容量
  }
}

[1]《STL源碼分析》----侯捷

[2]《STL3.0源碼》

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