#include1、首先,執行了代碼#include using namespace std; int main() { vector v; return 0; }
vector() _NOEXCEPT : _Mybase() { // construct empty vector } explicit vector(const _Alloc& _Al) _NOEXCEPT : _Mybase(_Al) { // construct empty vector, allocator }2、執行allocator
allocator() _THROW0() { // construct default allocator (do nothing) }3、進一步執行
_Vector_alloc(const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t(), _Al) { // construct allocator from _Al _Alloc_proxy(); }4、分配內存,初始化為0,經過一連串的調用,初始化結束
_Vector_val() { // initialize values _Myfirst = pointer(); _Mylast = pointer(); _Myend = pointer(); } pointer _Myfirst; // pointer to beginning of array pointer _Mylast; // pointer to current end of sequence pointer _Myend; // pointer to end of array };二、capacity
1、首先,vector 在VC 2008 中的實現比較復雜,雖然vector 的聲明跟VC6.0 是一致的,如下:
template < class _Ty, class _Ax = allocator<_Ty> > //第二參數是有默認參數的 class vector;
2、但在VC2008 中vector 還有基類,如下:
// TEMPLATE CLASS vector template < class _Ty, class _Ax > class vector : public _Vector_val<_Ty, _Ax> { };
3、稍微來看一下基類_Vector_val:
// TEMPLATE CLASS _Vector_val template < class _Ty, class _Alloc > class _Vector_val : public _CONTAINER_BASE_AUX_ALLOC<_Alloc> { // base class for vector to hold allocator _Alval protected: _Vector_val(_Alloc _Al = _Alloc()) : _CONTAINER_BASE_AUX_ALLOC<_Alloc>(_Al), _Alval(_Al) { // construct allocator from _Al } typedef typename _Alloc::template rebind<_Ty>::other _Alty; _Alty _Alval; // allocator object for values };
4、為了理解_Alty 的類型,還得看一下allocator模板類:
templateclass allocator { template<> class _CRTIMP2_PURE allocator { // generic allocator for type void public: template struct rebind { // convert an allocator to an allocator <_Other> typedef allocator<_Other> other; }; .... }; ... };
typedeftypename_Alloc::templaterebind<_Ty>::other_Alty; 整體來看是類型定義,假設現在我們這樣使用vector
如iteratornew_data =alloc.allocate(new_size); 注意,標准的vector::iterator 是以模板類實現的,下面的實現簡單地將其等同為指針,實際上真正的iterator 類的實現是內部有一個指針成員,指向容器元素。
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
對比list 的實現,繼承它的基類_List_nod 的一個成員 allocator<_Node> _Alnod; 如下:
typename _Alloc::template rebind<_Node>::other _Alnod; // allocator object for nodes
其中 _Node有三個成員,如下:
_Nodeptr _Next; // successor node, or first element if head
_Nodeptr _Prev; // predecessor node, or last element if head
_Ty _Myval; // the stored value, unused if head
如果是list
_Nodeptr _Pnode = this->_Alnod.allocate(1); // 即分配一個節點的空間,返回指向這個節點的指針。
實際上list 還繼承另外兩個基類的兩個成員,如下:
typename _Alloc::template rebind<_Nodeptr>::other _Alptr;// allocator object for pointers to nodes
typename _Alloc::template rebind<_Ty>::other _Alty _Alval; // allocator object for values stored in nodes
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
三、vector動態數組內部如何實現連續空間
1、通過跟蹤一個簡單的程序,觀察vector的capacity分配的過程,通過調試單步執行
#include#include using namespace std; int main() { vector v; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; v.push_back(1); cout << v.capacity() << endl; return 0; }
capacity 容量的計算方式如下:容量每次增長為原先容量 + 原先容量 / 2;
增長的源碼跟蹤結果如下:
size_type _Grow_to(size_type _Count) const { // grow by 50% or at least to _Count size_type _Capacity = capacity(); _Capacity = max_size() - _Capacity / 2 < _Capacity ? 0 : _Capacity + _Capacity / 2; // try to grow by 50% if (_Capacity < _Count) _Capacity = _Count; return (_Capacity); }
2、容量跟vector 大小的概念是不一樣的,capacity >= size,如下圖所示:
size 指的是_Mylast - _Myfirst 的區間;capacity 指的是 _Myend- _Myfirst的區間;也就是說存在尚未使用的空間。
當push_back 的時候往往帶有拷貝和析構多個操作,所以一下子分配比size() 大的空間capacity,可以減輕頻繁操作造成的效率問題。
通常,向量緩存了一部分內存空間,用來容納更多的元素,這樣,下一次插入新元素的時候,就不必重新分配內存,提高了插入速度。
四、內存分配器Allocatorallocator 模板類:
#includetemplate class allocator { public: T *allocate(size_t); void deallocate(T *, size_t); void construct(T *, size_t); void destroy(T *); //....... };
當然實際的接口沒實現沒那麼簡單,但大概實現的功能差不多:
allocate 調用operator new ;deallocate 調用 operator delete; construct 調用placement new (即在分配好的內存上調用拷貝構造函數),destroy 調用析構函數。
參考:
C++ primer 第四版
Effective C++ 3rd
C++編程規范