C語言資料結構之vector底層實現機制解析

2022-09-21 14:06:09 字數 2921 閱讀 2744

目錄

通過分析 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陣列。先看...