vector又稱為動態陣列,那麼動態體現在**?vector和一般的陣列又有什麼區別?vector中各個函式的實現原理是怎樣的,我們怎樣使用會更高效?
在容器類的最前面我們會看到許多的typedef ,常見的如下:
public:
typedef t value_type;
typedef value_type* pointer;
typedef value_type* iterator;
typedef t& reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
這些typedef 的意義在於:
在這裡我們只需要知道allocator類是vector類和底層記憶體之間的乙個中間層,遮蔽了記憶體分配,物件初始化的細節。
首先vector和普通陣列一樣,是在記憶體中連續分布的,然而它可以實現記憶體的動態分配(動態分配是指vector可以自動擴充自己的容量來滿足儲存元素的需要)。現有的申請到的記憶體空間不足以滿足動態陣列增長的需求時,vector會自動申請重新分配一塊更大的記憶體(也就是會自動進行一次reserve函式,在push_back不斷插入元素的時候,為了避免大量重新分配浪費效能,會將記憶體分配到原來的兩倍)
vector內部會維護三個指標,start 指標指向vector中的第乙個元素,end指標指向vector中最後乙個元素的後面,end_of_storage 申請到記憶體的最末端。為什麼要這樣設計?
可以在 o1 的時間 求出陣列內元素個數 和 容量(通過指標運算)
void destroyanddeallocate()
for(auto it = start; it != end; it++)
data_allocator.deallocate(start,end_of_storage-start);//由allocator**記憶體
}~vector()
void reallocate(size_type new_size = 0)
iterator new_start = data_allocator.allocate(new_size);//首先分配一塊新的記憶體
if(new_start == nullptr)
iterator new_end = ministl::uninitialized_copy(start, end, new_start);//移動元素
destroyanddeallocateall();//銷毀元素 並且 **記憶體
start = new_start;
end = new_end;
end_of_storage = start + new_size;// 設定指標位置
}
我們將從異常安全的角度來逐行分析**。
//這三行提供基本的異常安全保證
if(new_size == 0)
iterator new_start = data_allocator.allocate(new_size);//首先分配一塊新的記憶體
if(new_start == nullptr)
iterator new_end = ministl::uninitialized_copy(start, end, new_start);//may throw
destroyanddeallocateall();//析構函式 noexcept保證
//在最後替換成員指標,提供了強型別的異常安全保證
start = new_start;
end = new_end;
end_of_storage = start + new_size;// 設定指標位置
vector()
vector(size_t n, value_type val = value_type())//要求value_type 有乙個預設建構函式
vector(iterator first, iterator last)
vector(const vector&rhs)
vector(vector&&rhs)
}
value_type& operator (size_type n)
return *(start + n);
} value_type& front()
return *(start);
} value_type& back()
return *(end - 1);
}
void resize(size_type new_size, value_type val = value_type())
end = start + new_size;// 重新設定最後乙個元素位置
}else if (new_size < capacity())//小於申請到的記憶體容量
else // 重新分配記憶體
}void reserve(size_type n)
bool empty()
//modifiers
void push_back(value_type data)
void pop_back()
end--;
destroy(end);//析構
} templatevoid assign(inputiterator first, inputiterator last)
void assign(size_type n, const value_type &v)
iterator insert(iterator pos, const value_type &v)
if (size() == capacity())//記憶體申請
reallocate();
iterator new_end = end + 1;
data_allocator.construct(new_end, v);//要進行初始化否則會報錯
copy_backward(pos, end, new_end);//移動pos後面的元素到最終位置
*pos = v;//賦值
end = new_end;
end_of_storage++;
return pos;
} /*
這個函式比較複雜,一定注意end pos 的含義變化
*/iterator insert(iterator pos, const size_type &n, const value_type &val)
else //插入元素個數很多}/*
這個和上面大同小異
*/templatevoid insert(iterator pos, inputiterator first, inputiterator last)
else
}iterator erase(iterator pos)
iterator erase(iterator first, iterator last)
void clear()
void swap(vector&rhs)
bool operator==(vector& rhs)
return true;
}} bool operator!=(vector& rhs)
void operator=(const vector& rhs)
}};
templatevoid swap(vector& a, vector& b)
從零開始寫STL 模板元程式設計之tuple
class template std tuple is a fixed size collection of heterogeneous values.it is a generalization of std pair.可以用來在bind中儲存函式指標和引數 不定引數模板 模板偏特化 tuple作...
從零開始寫STL 二叉搜尋樹
二叉查詢樹 binary search tree 又 二叉搜尋樹,二叉排序樹 它或者是一棵空樹,或者是具有下列性質的二叉樹 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值 它的左 右子樹也分別為二叉排序樹。平均情況下插入查詢...
如何從零開始寫shell指令碼
如何從零開始寫shell指令碼 一 前言 為什麼我們需要使用shell 指令碼?難道我們之前學習的c c 不能夠完成shell指令碼語言的功能嗎,為什麼我們還需要學習shell指令碼?學習shell指令碼最大的好處是能夠輕易處理檔案與目錄之類的物件,如果同樣此類任務,利用c 或者c,則編寫程式很麻煩...