目錄
通過分析 vector 容器的源**不難發現,它就是使用 3 個迭代器(可以理解成指標)來表示的:
其中statrt指向vector 容器物件的起始位元組位置;
finish指向當前最後乙個元素的末尾位元組
end_of指向整個 vector 容器所占用記憶體空間的末尾位元組。
如圖 演示了以上這 3 個迭代器分別指向的位置
如圖 演示了以上這 2個迭代器分別指向的位置
在此基礎上,將 3 個迭代器兩兩結合,還可以表達不同的含義,例如:
start 和 finish 可以用來表示 vector 容器中目前已被使用的記憶體空間;
finish 和 end_of可以用來表示 vector 容器目前空閒的記憶體空間;
start和 end_of可以用表示 vector 容器的容量。
typedef t* iteratot;
typedef t* const_iteratot;
iteratot cend()const
iteratot cbegin()const
iteratot end()
iteratot begin()
vector的迭代器是乙個原生指標,他的迭代器和string相同都是操作指標來遍歷資料:
void reserve(size_t n)
}當 vector 的大小和容量相等(size==capacity)也就是滿載時,如果再向其新增元素,那麼 vector 就需要擴容。vector 容器擴容的過程需要經歷以下 3 步:
這也就解釋了,為什麼 vector 容器在進行擴容後,與其相關的指標、引用以及迭代器可能會失效的原因。
由此可見,vector 擴容是非常耗時的。為了降低再次分配記憶體空間時的成本,每次擴容時 vector 都會申請比使用者需求量更多的記憶體空間(這也就是 vector 容量的由來,即 capacity>=size),以便後期使用。
vector 容器擴容時,不同的編譯器申請更多記憶體空間的量是不同的。以 vs 為例,它會擴容現有容器容量的 50%。
使用memcpy拷貝問題
reserve擴容就是開闢新空間用memcpy將老空間的資料拷貝到新開空間中。
假設模擬實現的vector中的reserve介面中,使用memcpy進行的拷貝,以下**會發生什麼問題?
int main()
問題分析:
結論:如果物件中涉及到資源管理時,千萬不能使用memcpy進行物件之間的拷貝,因為memcpy是淺拷貝,否則可能會引起記憶體洩漏甚至程式崩潰。
void push_back(const t&var)
*final_end = var;
++final_end;
void pop_back()
插入問題一般先要判斷空間是否含有閒置空間,如果沒有,就要開闢空間。我們final_end==finally來判斷是否含有閒置空間。如果容器含沒有空間先開闢4位元組空間,當滿了後開2capacoity()空間。在final_end部插入資料就行了。對final_end加以操作。
iteratot insert(iteratot iterator,const t&var)
//插入操作
auto it = final_end;
while (it >= start+pos)
*iterator = var;
final_end++;
return iterator;
}假設這是一段vector空間要在pos插入資料,但是剛剛好final_end和final在同一位置,這個容器滿了,要對這這個容器做擴容操作。首先對開闢和這個空間的2唄大小的空間
接著把老空間資料拷貝到新空間中釋放老空間。
由於老空間釋放了pos指向的記憶體不見了。pos指標就成了野指標。
這如何解決呢就是在老空間解決之間儲存這個指標,接著讓他重新指向新空間的原來位置。
而insert()函式返回了這個位置迭代器這為迭代器失效提供了方法,這個方法就是重新賦值。讓這個指標重新指向該指向的位置。
iteratot erase(iteratot iterator) ;
vector vector_int(a, a + sizeof(a)/sizeof(int));
/*方案一*/
// for(int i = 0; i < vector_int.size(); i++)
// // }
/*方案二*/
// for(vector::iterator itor = vector_int.begin(); itor != vector_int.end(); ++itor)
// // }
/*方案三*/
vector::iterator v = vector_int.begin();
while(v != vector_int.end())
else}
/*方案四*/
// vector::iterator v = vector_int.begin();
// while(v != vector_i程式設計客棧nt.end())
// // else
// }
for(vector::iterator itor = vector_int.begin(); itor != vector_int.end(); itor++)
cout << endl;
return 0;
}一共有四種方案。
方案一表明vector可以用下標訪問元素,顯示出其隨機訪問的強大。並且由於vector的連續性,且for迴圈中有迭代器的自加,所以在刪除乙個元素後,迭代器需要減1。
方案二與方案一在迭代器的處理上是類似的,不過對元素的訪問採用了迭代器的方法。
方案三與方案四基本一致,只是方案三利用了erase()函式的返回值是指向下乙個元素的性質,又由於vector的性質(連續的記憶體塊),所以方案四在erase後並不需要對迭代器做加法。
資料結構之vector
vector是c 中的一種序列式容器,依靠其下標索引來訪問獲取容器內容。vector和array同為序列式容器,其資料格式 操作等方面都十分相似,其最大不同點在於它們對於記憶體空間的使用。array是靜態陣列,使用者必須把握好其資料數量,一次性分配合理的記憶體空間。否則array會在新增新元素而空間...
資料結構之向量vector
這裡將借助stl的vector 向量 實現動態陣列,並用它來管理資料。函式功能 複雜度size 返回向量的元素數 o 1 push back x 在向量尾新增元素x o 1 pop back 刪除向量的最後乙個元素 o 1 begin 返回指向向量開頭的迭代器 o 1 end 返回指向向量尾的迭代器...
資料結構 vector
vector是不定長陣列,也就是說它的長度是不固定的,簡單地說就是 按需分配 這聽上去似乎有點麻煩,但在宣告陣列時如果我們並不清楚陣列的長度,並且簡單粗暴地使用 define maxn 1000000會導致記憶體失去了夢想 就算不,仍有大量的記憶體成了鹹魚。這個時候,我們就需要vector陣列。先看...