最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言數(shù)據(jù)結(jié)構(gòu)之vector底層實現(xiàn)機制解析

 更新時間:2021年11月23日 11:47:09   作者:自首的小偷  
向量(Vector)是一個封裝了動態(tài)大小數(shù)組的順序容器(Sequence?Container)。跟任意其它類型容器一樣,它能夠存放各種類型的對象。可以簡單的認(rèn)為,向量是一個能夠存放任意類型的動態(tài)數(shù)組

一、vector底層實現(xiàn)機制刨析

在這里插入圖片描述

通過分析 vector 容器的源代碼不難發(fā)現(xiàn),它就是使用 3 個迭代器(可以理解成指針)來表示的:
其中statrt指向vector 容器對象的起始字節(jié)位置;
finish指向當(dāng)前最后一個元素的末尾字節(jié)
end_of指向整個 vector 容器所占用內(nèi)存空間的末尾字節(jié)。
如圖 演示了以上這 3 個迭代器分別指向的位置

在這里插入圖片描述

如圖 演示了以上這 2個迭代器分別指向的位置

在此基礎(chǔ)上,將 3 個迭代器兩兩結(jié)合,還可以表達不同的含義,例如:
start 和 finish 可以用來表示 vector 容器中目前已被使用的內(nèi)存空間;
finish 和 end_of可以用來表示 vector 容器目前空閑的內(nèi)存空間;
start和 end_of可以用表示 vector 容器的容量。

二、vector的核心框架接口的模擬實現(xiàn)

1.vector的迭代器實現(xiàn)

typedef T* Iteratot;
typedef T* const_Iteratot;

Iteratot cend()const {
			return final_end;
		}
		Iteratot cbegin()const {
			return start;
		}
			Iteratot end() {
			return final_end;
		}
		Iteratot begin() {
			return start;
		}

vector的迭代器是一個原生指針,他的迭代器和String相同都是操作指針來遍歷數(shù)據(jù):

  • begin()返回的是vector 容器對象的起始字節(jié)位置;
  • end()返回的是當(dāng)前最后一個元素的末尾字節(jié);

2.reserve()擴容

	void reserve(size_t n) {

			if (n > capacity()) {
				T* temp = new T  [n];
				//把statrt中的數(shù)據(jù)拷貝到temp中
				size_t size1 = size();
				memcpy(temp, start, sizeof(T*) * size());
			
				start = temp;
			  final_end = start + size1;
				finally = start + n;
			}
		}

當(dāng) vector 的大小和容量相等(size==capacity)也就是滿載時,如果再向其添加元素,那么 vector 就需要擴容。vector 容器擴容的過程需要經(jīng)歷以下 3 步:

  • 完全棄用現(xiàn)有的內(nèi)存空間,重新申請更大的內(nèi)存空間;
  • 將舊內(nèi)存空間中的數(shù)據(jù),按原有順序移動到新的內(nèi)存空間中;
  • 最后將舊的內(nèi)存空間釋放。

這也就解釋了,為什么 vector 容器在進行擴容后,與其相關(guān)的指針、引用以及迭代器可能會失效的原因。

由此可見,vector 擴容是非常耗時的。為了降低再次分配內(nèi)存空間時的成本,每次擴容時 vector 都會申請比用戶需求量更多的內(nèi)存空間(這也就是 vector 容量的由來,即 capacity>=size),以便后期使用。

vector 容器擴容時,不同的編譯器申請更多內(nèi)存空間的量是不同的。以 VS 為例,它會擴容現(xiàn)有容器容量的 50%。

使用memcpy拷貝問題
reserve擴容就是開辟新空間用memcpy將老空間的數(shù)據(jù)拷貝到新開空間中。
假設(shè)模擬實現(xiàn)的vector中的reserve接口中,使用memcpy進行的拷貝,以下代碼會發(fā)生什么問題?

int main()
{
bite::vector<bite::string> v;
v.push_back("1111");
v.push_back("2222");
v.push_back("3333");
return 0;
}

問題分析:

  • memcpy是內(nèi)存的二進制格式拷貝,將一段內(nèi)存空間中內(nèi)容原封不動的拷貝到另外一段內(nèi)存空間中
  • 如果拷貝的是自定義類型的元素,memcpy即高效又不會出錯,但如果拷貝的是自定義類型元素,并且自定義類型元素中涉及到資源管理時,就會出錯,因為memcpy的拷貝實際是淺拷貝。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

結(jié)論:如果對象中涉及到資源管理時,千萬不能使用memcpy進行對象之間的拷貝,因為memcpy是淺拷貝,否則可能會引起內(nèi)存泄漏甚至程序崩潰。

3.尾插尾刪(push_back(),pop_back())

	void push_back(const T&var) {
			if (final_end ==finally) {
				size_t newcode = capacity() == 0 ? 4 : capacity() * 2;

				reserve(newcode);
			}
			*final_end = var;
			++final_end;
		void pop_back() {
		
			final_end--;
		}

插入問題一般先要判斷空間是否含有閑置空間,如果沒有,就要開辟空間。我們final_end==finally來判斷是否含有閑置空間。如果容器含沒有空間先開辟4字節(jié)空間,當(dāng)滿了后開2capacoity()空間。在final_end部插入數(shù)據(jù)就行了。對final_end加以操作。

4.對insert()插入時迭代器失效刨析

		Iteratot insert(Iteratot iterator,const T&var) {
			assert(iterator <= final_end && iterator >= start);
			size_t pos = iterator - start;
			if (final_end == finally) {
				
				size_t newcode = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcode);	
			}
			//插入操作
			auto it = final_end;
			while (it >= start+pos) {
				*(it+1)=*it;
				it--;
			}
			*iterator = var;
			final_end++;
			
			return iterator;
		}

在這里插入圖片描述

假設(shè)這是一段vector空間要在pos插入數(shù)據(jù),但是剛剛好final_end和final在同一位置,這個容器滿了,要對這這個容器做擴容操作。首先對開辟和這個空間的2唄大小的空間

在這里插入圖片描述

接著把老空間數(shù)據(jù)拷貝到新空間中釋放老空間。

在這里插入圖片描述

在這里插入圖片描述

由于老空間釋放了pos指向的內(nèi)存不見了。pos指針就成了野指針。
這如何解決呢就是在老空間解決之間保存這個指針,接著讓他重新指向新空間的原來位置。

而insert()函數(shù)返回了這個位置迭代器這為迭代器失效提供了方法,這個方法就是重新賦值。讓這個指針重新指向該指向的位置。

5.對erase()數(shù)據(jù)刪除時迭代器失效刨析

	Iteratot erase(Iteratot iterator) {
				assert(iterator <= final_end && iterator >= start);
				auto it = iterator;
				while (it <final_end) {
					*it = *(it+1);
					it++;
				}
				final_end--;
				return iterator;
			}

在這里插入圖片描述

vector使用erase刪除元素,其返回值指向下一個元素,但是由于vector本身的性質(zhì)(存在一塊連續(xù)的內(nèi)存上),刪掉一個元素后,其后的元素都會向前移動,所以此時指向下一個元素的迭代器其實跟剛剛被刪除元素的迭代器是一樣的。
以下為解決迭代器失效方案:

#include <vector>
#include <iostream>
using namespace std;
 
int main()
{
    int a[] = {1, 4, 3, 7, 9, 3, 6, 8, 3, 3, 5, 2, 3, 7};
    vector<int> vector_int(a, a + sizeof(a)/sizeof(int));
 
 
 
 
/*方案一*/
    // for(int i = 0; i < vector_int.size(); i++)
    // {
    //     if(vector_int[i] == 3)
    //     {
    //         vector_int.erase(vector_int.begin() + i);
    //         i--;
    //     }
    // } 
 
/*方案二*/
    // for(vector<int>::iterator itor = vector_int.begin(); itor != vector_int.end(); ++itor)
    // {
    //     if (*itor == 3)
    //     {
    //         vector_int.erase(itor);
    //         --itor;
    //     }
 
    // }
 
/*方案三*/
vector<int>::iterator v = vector_int.begin();
while(v != vector_int.end())
{
    if(*v == 3)
    {
        v = vector_int.erase(v);
        cout << *v << endl;
    }
    else{
        v++;
    }
}
 
/*方案四*/
// vector<int>::iterator v = vector_int.begin();
// while(v != vector_int.end())
// {
//     if(*v == 3)
//     {
//         vector_int.erase(v); 
//     }
//     else{
//         v++;
//     }
// }
 
    for(vector<int>::iterator itor = vector_int.begin(); itor != vector_int.end(); itor++)
    {
        cout << * itor << "  ";
    }
    cout << endl;
    return 0;
}

一共有四種方案。

方案一表明vector可以用下標(biāo)訪問元素,顯示出其隨機訪問的強大。并且由于vector的連續(xù)性,且for循環(huán)中有迭代器的自加,所以在刪除一個元素后,迭代器需要減1。

方案二與方案一在迭代器的處理上是類似的,不過對元素的訪問采用了迭代器的方法。

方案三與方案四基本一致,只是方案三利用了erase()函數(shù)的返回值是指向下一個元素的性質(zhì),又由于vector的性質(zhì)(連續(xù)的內(nèi)存塊),所以方案四在erase后并不需要對迭代器做加法。

以上就是C語言數(shù)據(jù)結(jié)構(gòu)之vector底層實現(xiàn)機制解析的詳細(xì)內(nèi)容,更多關(guān)于C語言 vector底層機制的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++ LeetCode1780判斷數(shù)字是否可以表示成三的冪的和

    C++ LeetCode1780判斷數(shù)字是否可以表示成三的冪的和

    這篇文章主要為大家介紹了C++ LeetCode1780判斷數(shù)字是否可以表示成三的冪的和題解示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • C語言實現(xiàn)彈跳小球項目

    C語言實現(xiàn)彈跳小球項目

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)彈跳小球項目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • QT中在QLabel顯示圖片并且利用鼠標(biāo)點擊畫線問題

    QT中在QLabel顯示圖片并且利用鼠標(biāo)點擊畫線問題

    這篇文章主要介紹了QT中在QLabel顯示圖片并且利用鼠標(biāo)點擊畫線問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Pipes實現(xiàn)LeetCode(192.單詞頻率)

    Pipes實現(xiàn)LeetCode(192.單詞頻率)

    這篇文章主要介紹了Pipes實現(xiàn)LeetCode(192.單詞頻率),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C語言驅(qū)動開發(fā)之內(nèi)核通過PEB獲取進程參數(shù)

    C語言驅(qū)動開發(fā)之內(nèi)核通過PEB獲取進程參數(shù)

    PEB結(jié)構(gòu)(Process Envirorment Block Structure)其中文名是進程環(huán)境塊信息。本文將通過PEB實現(xiàn)獲取進程參數(shù),感興趣的小伙伴可以了解一下
    2022-10-10
  • Visual?Studio?Code?配置C、C++?文件debug調(diào)試環(huán)境的詳細(xì)過程

    Visual?Studio?Code?配置C、C++?文件debug調(diào)試環(huán)境的詳細(xì)過程

    這篇文章主要介紹了Visual?Studio?Code?配置C、C++?文件debug調(diào)試環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • C語言?深入理解動態(tài)規(guī)劃之計數(shù)類DP

    C語言?深入理解動態(tài)規(guī)劃之計數(shù)類DP

    動態(tài)規(guī)劃可謂是大名鼎鼎,筆試面試中的高頻考點,也是重點難點,動態(tài)規(guī)劃類型題目靈活多變,難度系數(shù)也相對較高,往往我們做不好動態(tài)規(guī)劃的題目就會與心儀的offer失之交臂,本篇文章我們就一起來研究一下動態(tài)規(guī)劃的計數(shù)類DP
    2022-04-04
  • C語言實現(xiàn)簡單學(xué)生信息管理系統(tǒng)

    C語言實現(xiàn)簡單學(xué)生信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C語言超詳細(xì)講解輪轉(zhuǎn)數(shù)組

    C語言超詳細(xì)講解輪轉(zhuǎn)數(shù)組

    這篇文章主要給大家講解輪轉(zhuǎn)數(shù)組的問題,一個問題不局限于一種解法,希望你看了本文的解決方法以后可以舉一反三自己編寫,這樣你的技術(shù)水平會有質(zhì)的提高
    2022-04-04
  • c語言snprintf函數(shù)的用法詳解

    c語言snprintf函數(shù)的用法詳解

    這篇文章主要給大家介紹了關(guān)于c語言snprintf函數(shù)用法的相關(guān)資料,snprintf()函數(shù)用于將格式化的數(shù)據(jù)寫入字符串,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09

最新評論

蚌埠市| 舒兰市| 徐水县| 怀来县| 高陵县| 偃师市| 加查县| 远安县| 且末县| 新蔡县| 正阳县| 彝良县| 手机| 齐齐哈尔市| 紫金县| 安龙县| 太谷县| 兴宁市| 富顺县| 阿勒泰市| 天长市| 昭平县| 株洲市| 江山市| 南丹县| 淮滨县| 晋江市| 乐平市| 乌海市| 山阳县| 阿坝县| 那曲县| 五华县| 依安县| 保山市| 察隅县| 信阳市| 木里| 峡江县| 临武县| 曲周县|