Learning C++ No.14【STL No.4】
引言:
北京時(shí)間:2023/3/9/12:58,下午兩點(diǎn)有課,現(xiàn)在先把引言給搞定,這樣就能激勵(lì)我更早的把這篇博客給寫完了,萬(wàn)事開頭難這句話還是很有道理的,剛好利用現(xiàn)在昏昏欲睡的時(shí)候,把這個(gè)沒(méi)什么干貨的引言寫完,并且剛剛刷了一下知乎,我發(fā)現(xiàn)現(xiàn)在的知乎有兩個(gè)字很合適形容(掘金),例,我剛剛隨意看了一個(gè)有關(guān)大學(xué)生4年應(yīng)該干什么的文章,寫這種文章的,我不多做評(píng)價(jià),我深信人無(wú)完人這一理念,我深知自己并不優(yōu)秀,但我知道,我的三觀還行,例如:我并不覺(jué)得送外賣……(可能有人說(shuō)……),我反而時(shí)常會(huì)想象自己熬夜送外賣的場(chǎng)景,我覺(jué)得這樣還挺好的,憑自己的雙手賺錢;什么叫上好大學(xué)……,什么叫高考……,什么叫富二代……,我只想好好看電視,好好吃飯,找一個(gè)能聊的來(lái)的朋友,所以像什么吹牛比自卑好,我不能理解,反正我寧愿自卑我都不愿意吹牛,做人不是為了給別人增加壓力,開玩笑的吹牛叫搞笑,認(rèn)真的吹牛叫說(shuō)謊,所以咱還是繼續(xù)自卑吧!做不到的事情、未可知的事情,咱不干,咱只談實(shí)際,咱做好自己,例,美劇……,ok,這篇博客,我們就繼續(xù)深入學(xué)習(xí)迭代器失效的問(wèn)題,和vector類知識(shí)的收尾,然后把list(帶頭雙向循環(huán)鏈表)給開個(gè)頭(下篇博客就是自我實(shí)現(xiàn)list),So,gogogo!
前提:此時(shí)的我,因?yàn)樯衔鐚懲炅艘黄┛?#xff0c;現(xiàn)在心情非常的好,只是有點(diǎn)困,并且以我的情商,舍友之間關(guān)系還是非常的ok的(只是有點(diǎn)可惜,沒(méi)能找到能談心的),校園人際關(guān)系也還行(畢竟我沒(méi)有什么認(rèn)識(shí)的人,哈哈哈!),上述只是對(duì)知乎上的某些清華級(jí)別文章做出的感想!并且通過(guò)文字證明:耍嘴我也行,哈哈哈!好在這里沒(méi)有吹牛!寫(耍嘴我才是祖師爺!),哈哈哈!其實(shí)我也只會(huì)哈哈哈,別的我也不是很在行,哈哈哈!看到這么多哈哈哈,這里剛好想起來(lái),明天5哈(綜藝)就更新了哦!又不會(huì)無(wú)聊啦!(不過(guò)談到5哈,這里我對(duì)當(dāng)今的綜藝情況也是略有一點(diǎn)見(jiàn)解的),這里就不多做贅述了,此處省略一萬(wàn)字……
再談迭代器失效問(wèn)題
上篇博客,我們已經(jīng)搞明白了插入函數(shù)迭代器失效的原因和解決的方法,這里我們不多加深入,這里我們就通過(guò)刪除函數(shù)(erase),來(lái)再次進(jìn)入到迭代器失效的問(wèn)題上,如下圖:
此時(shí)按照上述代碼的寫法,我們就可以發(fā)現(xiàn),在刪除數(shù)據(jù)的時(shí)候,會(huì)導(dǎo)致_finish(end)的位置減減到pos(it)位置的前面,這樣就會(huì)導(dǎo)致地址不匹配(pos再也找不到迭代器區(qū)間的地址),這個(gè)問(wèn)題也就是另一個(gè)經(jīng)典的迭代器失效問(wèn)題;
所以當(dāng)我們按照上述代碼的寫法,只要有兩個(gè)偶數(shù)同時(shí)在一起或者結(jié)尾是一個(gè)偶數(shù)的話,就會(huì)導(dǎo)致跳過(guò)一個(gè)偶數(shù)或者導(dǎo)致_finish(end)的位置減減到pos(it)位置的前面,這些情況都是迭代器失效的問(wèn)題;
本質(zhì)就是pos(it)和_finish(end)不能匹配成功,會(huì)發(fā)生跳躍和穿越的問(wèn)題
解決方法
上篇博客,我們知道,解決這種問(wèn)題就是使用返回值就行了(目的就是為了讓地址連續(xù)),所以此時(shí)解決這個(gè)刪除函數(shù)中迭代器失效問(wèn)題,最好的方式還是使用返回值,如下代碼:
以上就是使用返回值的方式解決迭代器問(wèn)題,所以以后碰到刪除和插入,我們都應(yīng)該要考慮一下是否涉及到迭代器失效的問(wèn)題(前提我們使用的遍歷方式是迭代器或者范圍for),如果碰到這些問(wèn)題,導(dǎo)致程序崩潰,此時(shí)我們也不要慌張,第一時(shí)間就應(yīng)該要想到使用返回值的范式就可以很好的解決這個(gè)問(wèn)題,迭代器實(shí)現(xiàn)問(wèn)題,So,So啦!
總:只要我們使用了迭代器來(lái)遍歷數(shù)據(jù),那么就要考慮到迭代器失效的問(wèn)題哦!
從模板再談匿名對(duì)象
在之前學(xué)習(xí)類和對(duì)象的時(shí)候,我們了解了匿名對(duì)象的概念,知道它就是從 vector<int> v; v.vector();直接寫成vector<int>().vector()的一個(gè)簡(jiǎn)單省略寫法,并且此時(shí)如果寫成模板參數(shù)的形式,就可以寫成 T().push_back(),表示的就是:使用T(int)類型去創(chuàng)建一個(gè)匿名對(duì)象,然后使用這個(gè)對(duì)象去調(diào)用push_back(尾插函數(shù)),也就可以寫成T(),表示的就是使用默認(rèn)構(gòu)造函數(shù),生成一個(gè)該默認(rèn)構(gòu)造函數(shù)類型的匿名對(duì)象,并且最后為了更好的配合模板初始化問(wèn)題的使用,C++的大佬,是允許這樣寫的:const T& x = T()使用給匿名對(duì)象起別名的方式,來(lái)延長(zhǎng)匿名對(duì)象的生命周期(否匿名對(duì)象的生命周期只在該行代碼,出了作用域就失效,所以以后看到這種寫法,我們不要感到奇怪,當(dāng)然更重要的是,在以后我們遇到有關(guān)模板類初始化的時(shí)候,我們也可以使用這樣的寫法。注意:一定要加上const,不可以寫成T& x = T(),因?yàn)檎{(diào)用默認(rèn)構(gòu)造函數(shù)的時(shí)候,都是通過(guò)臨時(shí)變量的形式,臨時(shí)變量是具有常屬性的,所以如果沒(méi)有const,語(yǔ)法上就是有問(wèn)題的。
如下就是使用匿名對(duì)象去構(gòu)造我的模板類自我實(shí)現(xiàn)構(gòu)造函數(shù):
迭代器特性
從源碼中的構(gòu)造函數(shù)再看迭代器,如下圖:
我們可以發(fā)現(xiàn),vector類的構(gòu)造函數(shù)中,有一個(gè)構(gòu)造函數(shù)是支持傳兩個(gè)隨機(jī)迭代器參數(shù)調(diào)用構(gòu)造函數(shù)的(本質(zhì)就是允許傳兩個(gè)指針(地址)給給構(gòu)造函數(shù)中的隨機(jī)迭代器函數(shù)),所以有了這個(gè)迭代器構(gòu)造函數(shù),那么此時(shí)調(diào)用構(gòu)造函數(shù)的時(shí)候,就可以進(jìn)行如下的調(diào)用:
可以發(fā)現(xiàn),只要我們有了一個(gè)迭代器類型參數(shù)的構(gòu)造函數(shù),那么此時(shí)不僅可以對(duì)vector類型的數(shù)據(jù)調(diào)用構(gòu)造函數(shù)、對(duì)string類型的數(shù)據(jù)調(diào)用構(gòu)造函數(shù),而且還可以對(duì)數(shù)組調(diào)用構(gòu)造函數(shù),所以總的來(lái)說(shuō),迭代器本上就是調(diào)用地址,只要我們傳遞的參數(shù)是地址類型(指針),并且迭代器類型符合(雙向迭代器、單向迭代器、隨機(jī)迭代器),那么就可以使用迭代器來(lái)訪問(wèn)我們的數(shù)據(jù)。
總:此時(shí)無(wú)論是迭代器失效問(wèn)題還是迭代器使用問(wèn)題,我們都進(jìn)行了進(jìn)一步的理解,所以迭代器的學(xué)習(xí),我們先告一段落,不過(guò)在以后的鏈表和二叉樹學(xué)習(xí)過(guò)程中,我們肯定會(huì)再和它打交道了,并且更加深入的了解它。
再談深淺拷貝
搞定了迭代器這個(gè)重要的話題,此時(shí)我們就再來(lái)看一個(gè)重要的問(wèn)題,深淺拷貝問(wèn)題,再談原因:當(dāng)我們遇到了深拷貝之后,新空間的數(shù)據(jù)還是一個(gè)類(也就是還指向了一塊空間,還需要進(jìn)行深拷貝),此時(shí)就會(huì)因?yàn)?#xff0c;如果只進(jìn)行一次深拷貝的話,那么導(dǎo)致舊空間中的數(shù)據(jù)指向的那塊空間,會(huì)被兩個(gè)不同空間(新空間、舊空間)中的數(shù)據(jù)類型(指針)一起存儲(chǔ),最后就會(huì)導(dǎo)致該空間被析構(gòu)兩次,導(dǎo)致程序崩潰。 有了這個(gè)問(wèn)題,那么此時(shí)=我們就需要再進(jìn)一步的了解一下深淺拷貝問(wèn)題了!
第一個(gè)涉及這種場(chǎng)景:調(diào)用拷貝構(gòu)造的時(shí)候
第二個(gè)涉及這種場(chǎng)景:擴(kuò)容的時(shí)候
在談這兩個(gè)場(chǎng)景之前之前,我們淺淺復(fù)習(xí)一下之前的知識(shí):this指針和賦值運(yùn)算符重載
this指針
學(xué)習(xí)類和對(duì)象,this指針是非常的重要的,因?yàn)閠his指針是C++大佬專門發(fā)明出來(lái)在類和對(duì)象中使用的,目的就是為了可以讓我們?cè)谡{(diào)用類中的公有成員函數(shù)的時(shí)候,可以少傳一個(gè)參數(shù),默認(rèn)this指針代表的就是該類對(duì)象(并且this指針可以省略),所以就導(dǎo)致我們可以不需要傳參(類對(duì)象),就可以使用某個(gè)類對(duì)象,如下圖:
我們可以發(fā)現(xiàn),我們的函數(shù)中,只有三個(gè)參數(shù),但是此時(shí)我們卻可以使用該類的私有成員變量,原因就是,我們的類對(duì)象(d1),去調(diào)用了該公有成員函數(shù)(Init),所以此時(shí)編譯器就默認(rèn)該對(duì)象(d1)就是this指針,并且默認(rèn)它的地址被傳給了該公有成員函數(shù)(Init),并且默認(rèn)這個(gè)地址參數(shù)是被this指針接收,所以就導(dǎo)致,在類中的公有成員函數(shù)都有一個(gè)默認(rèn)的參數(shù)存在,就是this指針,有了這個(gè)默認(rèn)的指針,此時(shí)就允許該類的任意對(duì)象直接來(lái)調(diào)用該類中的公有成員函數(shù)。
注意:此時(shí)小心空指針對(duì)象成為this指針的情況(容易導(dǎo)致空指針解引用問(wèn)題)
賦值運(yùn)算符重載
首先第一點(diǎn),賦值運(yùn)算符重載是一個(gè)默認(rèn)成員函數(shù),它是六大天選之子之一,你不寫編譯器會(huì)自己調(diào)用(無(wú)論是內(nèi)置類型還是自定義類型(但是只是淺拷貝(如果涉及到深拷貝問(wèn)題,就需要自己去實(shí)現(xiàn)一個(gè)深拷貝的拷貝構(gòu)造函數(shù)(因?yàn)榭截悩?gòu)造函數(shù)由于使用了賦值運(yùn)算符,所以也可以直接對(duì)內(nèi)置類型和自定義類型進(jìn)行初始化)))),所以如果涉及到了深拷貝問(wèn)題,那么你就需要自己去實(shí)現(xiàn)賦值運(yùn)算符重載和一系列的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù),(因?yàn)榫幾g器會(huì)優(yōu)先調(diào)用我們自己實(shí)現(xiàn)的函數(shù),其次才是對(duì)自定義類型調(diào)用相應(yīng)的默認(rèn)成員函數(shù))。
六大默認(rèn)成員函數(shù)和自定義類型、內(nèi)置類型的關(guān)系總的來(lái)說(shuō)就是兩句話:
默認(rèn)構(gòu)造函數(shù)和析構(gòu)函數(shù),對(duì)內(nèi)置類型不處理,自定義類型調(diào)用其對(duì)應(yīng)的函數(shù);
拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載,不僅對(duì)自定義類型進(jìn)行處理,對(duì)內(nèi)置類型也會(huì)處理(但只是淺拷貝);
從拷貝構(gòu)造看深淺拷貝:
復(fù)習(xí)完上述的知識(shí),我們就可以開始新知識(shí)的學(xué)習(xí)了,問(wèn)題如上描述(深拷貝出來(lái)的新空間中,還有深拷貝),如下圖:
根據(jù)上圖,我們就可以充分意識(shí)到,遇到類中類問(wèn)題的解決方法和基本情形了,所以以后想要使用memcpy函數(shù),就一定要考慮是否涉及深層次的深拷貝問(wèn)題,如果有,就不可以使用memcpy函數(shù),而是去循環(huán)調(diào)用賦值運(yùn)算符重載(前提是該類具有賦值運(yùn)算符重載)。
從擴(kuò)容函數(shù)看深淺拷貝
搞定了上述拷貝構(gòu)造函數(shù)中的深層次深拷貝問(wèn)題,發(fā)現(xiàn)原因是因?yàn)閙emcpy只能進(jìn)行淺拷貝的問(wèn)題,此時(shí)就想到,我們的擴(kuò)容函數(shù)中,也使用了memcpy函數(shù),所以此時(shí)我們就應(yīng)該要想到,擴(kuò)容函數(shù)是否也會(huì)涉及深層次的拷貝問(wèn)題,相信我,答案是會(huì)的,如圖:
因?yàn)榈览矶疾畈欢?#xff0c;這里不多做講解
總:我們對(duì)奇怪知識(shí)的理解又多了一點(diǎn)點(diǎn),深層次的深拷貝問(wèn)題So、So!
vector較完整代碼如下
#include<iostream> #include<string> #include<stdlib.h> #include<string.h> #include<assert.h> #include<algorithm>//包含所有算法的頭文件,例如:sort #include<functional>//排降序的時(shí)候用到 using namespace std;namespace wwx2 {template<class T>class my_vector{public://可以看出上述是把T給直接定義成了一個(gè)value_type,然后使用value_type定義了const指針和普通指針(所以本質(zhì)上:都只是T類型而已)typedef T* iterator;//有普通版本的迭代器,此時(shí)無(wú)論是因?yàn)槟7耂TL還是真的會(huì)用到,我們都應(yīng)該要給一個(gè)const類型的迭代器typedef const T* const_iterator;typedef T& value_type;typedef size_t size_type;my_vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)//初始化列表初始化{}my_vector(size_type n, const T& val = T()) //和下述的那個(gè)resize同理(使用T匿名對(duì)象調(diào)用默認(rèn)構(gòu)造函數(shù),然后增長(zhǎng)匿名對(duì)象的生命周期): _start(nullptr), _finish(nullptr), _end_of_storage(nullptr){//所以無(wú)論這個(gè)類是什么類型,在初始化的時(shí)候,我們就是給給它的默認(rèn)構(gòu)造就行了reserve(n);for (size_type i = 0; i < n; ++i){push_back(val);}}//此處可以添加一個(gè)上述構(gòu)造函數(shù)的int重載版本(省略)//使用迭代器區(qū)間的一個(gè)構(gòu)造函數(shù)(實(shí)現(xiàn)了這個(gè)函數(shù),此時(shí)就會(huì)導(dǎo)致下面的那個(gè)調(diào)用構(gòu)造函數(shù)初始化時(shí),不知道調(diào)用那個(gè)了,因?yàn)榇藭r(shí)有兩個(gè)構(gòu)造函數(shù)),就會(huì)導(dǎo)致類型不匹配問(wèn)題,因?yàn)槭褂玫鞯臉?gòu)造函數(shù),是要求傳指針參數(shù)的,不可以是整形參數(shù),所以需要改進(jìn)一下(蘿卜青菜區(qū)分開來(lái))template <class InputIterator>//此時(shí)就是一個(gè)模板類中有模板函數(shù)的寫法(本質(zhì)上是因?yàn)榈鞯亩鄻有?#xff0c;不可以把迭代器的類型給寫死,要是可變的,所以就使用模板的方式)my_vector(InputIterator first, InputIterator last)//就是一個(gè)允許類模板的成員函數(shù)是一個(gè)函數(shù)模板: _start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while (first != last)//迭代器區(qū)間:[first,last){push_back(*first);++first;}}//上面的兩個(gè)構(gòu)造函數(shù)對(duì)比,如果,下面?zhèn)魃蟻?lái)的參數(shù)是兩個(gè)整形,那么此時(shí)因?yàn)榈谝粋€(gè)構(gòu)造函數(shù)的第一個(gè)參數(shù)是一個(gè)無(wú)符號(hào)數(shù)(所以此時(shí)需要進(jìn)行類型的轉(zhuǎn)換)//而第二個(gè)構(gòu)造函數(shù)的兩個(gè)參數(shù)由于都是指針,所以就可以直接接收,不需要什么類型轉(zhuǎn)換(所以第二個(gè)構(gòu)造函數(shù)就是下述傳參更愛(ài)吃的蘿卜)//所以如果是兩個(gè)整形使用了第二個(gè)構(gòu)造函數(shù),那么此時(shí)就會(huì)導(dǎo)致對(duì)整形就行解引用的情況發(fā)生,所以就有問(wèn)題了//這個(gè)位置還可以加一個(gè)給拷貝構(gòu)造使用的構(gòu)造函數(shù)(如果沒(méi)有這個(gè)拷貝構(gòu)造函數(shù),而是去調(diào)用構(gòu)造函數(shù)的話,這邊就會(huì)導(dǎo)致經(jīng)典的淺拷貝問(wèn)題)//my_vector(const my_vector<T>& v)//因?yàn)檎{(diào)用拷貝構(gòu)造的時(shí)候,傳參傳上來(lái)的是一個(gè)vector的對(duì)象,所以這邊的參數(shù)也要寫成vector,不可以像上述一樣寫成別的類型//{//因?yàn)樯鲜鲆呀?jīng)有了一個(gè)有缺省參數(shù)的構(gòu)造函數(shù),所以這里不需要再給(總的來(lái)說(shuō),還是拷貝構(gòu)造的特性)// reserve(v.capacity());//深拷貝,不然就會(huì)導(dǎo)致同一塊空間析構(gòu)兩次// for (auto e : v)// {// push_back(e);//這個(gè)是因?yàn)閺?fù)用了reserve和push_back(不傳統(tǒng))// }//}//my_vector(const my_vector<T>& v)//傳統(tǒng)一些的深拷貝寫法//{// reserve(v.capacity());// memcpy(_start, v._start, sizeof(T) * v.size());//這步需要仔細(xì)研究一下(本質(zhì)還是那個(gè)道理,反正三指針問(wèn)題一定要給它搞定)// _finish = _start + v.size();//這邊因?yàn)開finish是由數(shù)據(jù)個(gè)數(shù)決定的,所以新開辟的空間之中有多少個(gè)數(shù)據(jù)是會(huì)改變的,所以這邊的_finish是需要自己更新一下的,不可以依靠reserve中的_finish(但是reserve中的容量是可以使用的,因?yàn)殚_辟空間的大小是不會(huì)改變的)//}my_vector(const my_vector<T>& v)//最傳統(tǒng)的深拷貝寫法{_start = new T[v.capacity()];//memcpy(_start, v._start, sizeof(T) * size());//所以為了解決深深拷貝的問(wèn)題,此時(shí)就不可以使用memcpy函數(shù),而是去循環(huán)調(diào)用賦值(因?yàn)橘x值運(yùn)算符本質(zhì)上就是深拷貝實(shí)現(xiàn)的)for (size_type i = 0; i < v.size(); ++i)//調(diào)用賦值運(yùn)算符,然后通過(guò)復(fù)制運(yùn)算符再去調(diào)用拷貝構(gòu)造{ _start[i] = v._start[i];//此時(shí)這樣寫,我們就解決了深拷貝中還要深拷貝的問(wèn)題(本質(zhì):就是構(gòu)造函數(shù)中嵌套構(gòu)造函數(shù))}//并且因?yàn)榘凑丈鲜瞿菢訉?#xff0c;對(duì)內(nèi)置類型并沒(méi)有影響,因?yàn)閺?fù)制對(duì)內(nèi)置類型來(lái)說(shuō)也是可以用的(賦值重載本來(lái)就是六大默認(rèn)函數(shù)之一,編譯器會(huì)自己調(diào)用)_finish = _start + v.size();_end_of_storage = _start + v.capacity();//reserve是會(huì)處理容量的,所以沒(méi)有使用reserve的時(shí)候,就要自己把容量的大小給處理一下}~my_vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}iterator begin(){return _start;//通過(guò)臨時(shí)變量返回,就是類型傳值返回}iterator end(){return _finish;//同理}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}size_type capacity()const//像這種函數(shù)一定要記得加上我們的const{return _end_of_storage - _start;}size_type size()const{return _finish - _start;}void resize(size_type n, T val = T())//實(shí)現(xiàn)了reserve,此時(shí)resize復(fù)用就行,只是初始化的細(xì)節(jié)注意一下和size的大小注意一下就行 (所以此時(shí)我們就需要多給一個(gè)缺省參數(shù),來(lái)進(jìn)行默認(rèn)的初始化新開辟的空間),就是防止你沒(méi)有給第二個(gè)參數(shù),只給了第一個(gè)參數(shù),那此時(shí)我也可以把空間初始化{//上面那個(gè)缺省值的初始化是非常的神奇的(目的:因?yàn)榇藭r(shí)的vector是一個(gè)泛型編程,是沒(méi)有具體類型的,所以不可以用0來(lái)初始化,所以就要用一個(gè)模板參數(shù),然后就是通過(guò)一個(gè)匿名對(duì)象的方式去調(diào)用默認(rèn)構(gòu)造函數(shù))if (n < size())//這個(gè)不是縮容(這個(gè)屬于刪除數(shù)據(jù),因?yàn)閟ize是和數(shù)據(jù)緊緊掛鉤的){_finish = _start + n;//這個(gè)條件在尾插的時(shí)候,擴(kuò)容,是不可能存在縮容刪除數(shù)據(jù)的(唯一可能的就是我們直接調(diào)用這個(gè)函數(shù),然后進(jìn)行傳參的時(shí)候,只有這種情況才有可能導(dǎo)致刪除)}else{if (n > capacity()) //這個(gè)條件就是傳說(shuō)中的只有你比我小,我才擴(kuò)容 {reserve(n);//開空間}while (_finish != _start + n)//加 初始化{*_finish = val;//此時(shí)已經(jīng)有空間了,所以就不需要使用定位new的方法,直接賦值就行++_finish;}}}value_type operator[](size_type pos)//并且此時(shí)返回的是一個(gè)引用,就是返回別名,目的:節(jié)省構(gòu)造,防止臨時(shí)變量的常屬性{assert(pos < size());return _start[pos];//就是返回這個(gè)pos位置在_statr中的那個(gè)下標(biāo)位置(因?yàn)榇藭r(shí)是指針,所以準(zhǔn)確的來(lái)說(shuō),應(yīng)該是一個(gè)地址位置)}const value_type operator[](size_type pos)const//就是多重載一個(gè)const類型的,給給const對(duì)象使用(蘿卜青菜給有所愛(ài)){assert(pos < size());return _start[pos];}void reserve(size_type n){//這邊肯定是要涉及深淺拷貝問(wèn)題的(并且為了防止縮容問(wèn)題,這邊還要進(jìn)行判斷)if (n > capacity()){//使用下面調(diào)換兩個(gè)指針的順序是可以解決的,但是不是很好,所以我們這邊直接先把size()的值給接收起來(lái)就行size_type sz = size();//這樣直接使用sz就行了,不需要再使用size(),也就是不需要再考慮finish和start的位置(隨便它去變,跟我都沒(méi)關(guān)系)iterator tmp = new T[n];//此時(shí)這里不需要考慮加1的問(wèn)題(只有像string這種,需要存一個(gè)\0的這種,我們才需要多開一個(gè)空間給給它使用)if (_start != nullptr)//此時(shí)的new是不需要想malloc一樣就行開辟成功和失敗的判斷的,這個(gè)只是為了單純判斷一下_start中是否有數(shù)據(jù){// memcpy(tmp, _start, sizeof(T) * size());//由于自定義類型不適用,所以改進(jìn)一下for (size_type i = 0; i < sz; ++i)//深深拷貝的專業(yè)寫法,間接多調(diào)用一次拷貝構(gòu)造{tmp[i] = _start[i];}delete[] _start;//這個(gè)就是經(jīng)典的防止空間太大太小問(wèn)題,直接開空間,然后拷貝,然后直接把原空間給刪除}//_start = tmp;//注意:因?yàn)榇藭r(shí)是重新開空間,釋放舊空間,所以此時(shí)的tmp就是我們的start//注意:此時(shí)下述的size()是不會(huì)因?yàn)閒inish和start的地址改變而改變的 (不會(huì)因?yàn)橹貜?fù)調(diào)用而改變),一直都是同一個(gè)值,也就導(dǎo)致可以直接使用tmp+size()//_finish = tmp + size(); //如果此時(shí)是先把tmp給給_start,然后再加加size(),此時(shí)就會(huì)導(dǎo)致finish還是0,而start已經(jīng)是tmp,然后又因?yàn)閟ize就是finish-start,就會(huì)導(dǎo)致size是一個(gè)負(fù)值,也就是-start,然后再用start+size,那么剛好就是0,最后賦值給finish,此時(shí)finish就還是0,所以就會(huì)導(dǎo)致后面push_back的時(shí)候,對(duì)空指針解引用的問(wèn)題,所以此時(shí)為了解決這個(gè)問(wèn)題,此時(shí)就不敢直接先給給start_start = tmp;//先給給finish,再給給start就行,很好的解決finish為空的問(wèn)題_finish = tmp + sz;//提前記錄size的好處_end_of_storage = tmp + n;//此時(shí)的這個(gè)是通過(guò)tmp指針的首地址,然后加上16個(gè)字節(jié),就是首地址向后走走16個(gè)字節(jié),得到的就是此時(shí)的容量}}void push_back(const T& x){//因?yàn)槭褂玫氖悄0孱?#xff0c;所以這里的參數(shù)類型都是直接給一個(gè)T參數(shù)類型就可以了//從剛剛的STL源碼中,我們可以發(fā)現(xiàn)的是,它的push_back使用的是內(nèi)存池開空間的形式(就是定義new加定義構(gòu)造)//我們這里使用不了,我們就直接使用正常的形式就行(如果想要使用的話,就要在定義模板參數(shù)的位置給一個(gè)內(nèi)存池的參數(shù))if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);//此時(shí)的reserve函數(shù)中使用的是賦值運(yùn)算符重載而不是memcpy,可以放心大膽的使用}*_finish = x;//這步就是尾插的經(jīng)典步驟,上述的判斷只是為了防止空間不足而已(但是由于我們的_end是一個(gè)原生指針,所以這里想要直接在尾部賦值,就需要對(duì)這個(gè)尾部指針進(jìn)行解引用)++_finish;}void pop_back(){assert(!empty());//切記assert給的是真--_finish;//這種如果直接用,不檢查的話,就會(huì)導(dǎo)致刪多了的話有越界問(wèn)題(并且因?yàn)榇藭r(shí)是迭代器的寫法,地址問(wèn)題),就會(huì)導(dǎo)致循環(huán)找地址,然后就導(dǎo)致無(wú)限打印地址,直到地址匹配到}iterator insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);//還是那個(gè)道理,assert中的條件是真條件//并且由于這邊,我們使用了_finish這個(gè)位置,就會(huì)導(dǎo)致,如果容量剛好等于_finish的時(shí)候,越界,所以這個(gè)位置也要進(jìn)行一個(gè)容量的檢查if (_finish == _end_of_storage){size_type len = pos - _start;//先記錄(len的作用就是解決迭代器失效問(wèn)題,目的:更新pos指針)reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;//擴(kuò)容后再更新(解決迭代器失效問(wèn)題)}iterator end = _finish - 1;while (end >= pos)//此時(shí)因?yàn)閜os的類型是地址,所以不存在-1變成無(wú)符號(hào)(size_t),所以不存在死循環(huán),沒(méi)有問(wèn)題{*(end + 1) = *end;//此時(shí)的意思就是把最后一個(gè)數(shù)據(jù)賦值給0,然后把剛剛那個(gè)位置騰出來(lái),然后循環(huán)--end;}*pos = val;++_finish;return pos;}iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator start = pos + 1;while (start != _finish){*(start - 1) = *start;++start;}--_finish;return pos;//這個(gè)位置不敢給成start,因?yàn)楸举|(zhì)就是為了更新pos}bool empty(){return _start == _finish;//當(dāng)_finish--到_start的時(shí)候,就是空,就是不允許的}private:iterator _start;//因?yàn)镾TL源碼中是直接使用三個(gè)原生指針,所以這邊我們模仿它,我們也直接使用三個(gè)原生指針就行iterator _finish;iterator _end_of_storage;/* iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;*///這樣寫就可以不需要在構(gòu)造函數(shù)的初始化列表位置寫初始化了,因?yàn)榈綍r(shí)候他自己會(huì)調(diào)用這下面的缺省參數(shù)};void test_my_vector1(){wwx2::my_vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;my_vector<int>::iterator it = v.begin();//所以本質(zhì),我發(fā)現(xiàn),使用三指針的寫法,好像就是為了可以更好的使用迭代器(因?yàn)榈鞯谋举|(zhì)就是地址的加加減減,前提:地址要連續(xù))while (it != v.end())//不連續(xù)就會(huì)導(dǎo)致迭代器失效問(wèn)題{cout << *it << " ";++it;}cout << endl;for (auto e : v)//有了迭代器,就有迭代器的小兒子范圍for{cout << e << " ";}cout << endl;}void test_my_vector2(){wwx2::my_vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.pop_back();v.pop_back();my_vector<int>::iterator it = v.begin();my_vector<int>::const_iterator cit = v.begin();//反正就是蘿卜青菜給有所愛(ài),數(shù)據(jù)類型是什么就調(diào)用什么,不怕沒(méi)有,想要什么就有什么while (it != v.end()){cout << *it << " ";++it;}cout << endl;}template<class T>void Function(){ T x = T();//這個(gè)就直接用一個(gè)int類型來(lái)輔助理解就行(int x = int();) 可以看出此時(shí)的int();就是我們之前學(xué)的匿名對(duì)象;其中int 空表示的就是匿名對(duì)象,而int()后面的括號(hào)其實(shí)表示的是,此時(shí)拿著這個(gè)int空,匿名對(duì)象去調(diào)用某一個(gè)函數(shù),()括號(hào)中存放的本就應(yīng)該是你要調(diào)用的這個(gè)函數(shù)需要的參數(shù)cout << x << endl;//總而言之:目的就是為了讓任意類型都可以調(diào)用默認(rèn)構(gòu)造,然后任意類型都可以初始化}void test_my_vector3(){//int i = int();//這個(gè)的意思就是:使用int(),匿名對(duì)象,然后去調(diào)用構(gòu)造函數(shù),然后延長(zhǎng)匿名對(duì)象的聲明周期(把它給給新的對(duì)象)//int j = int(1);//支持這種寫法,本質(zhì)上還是為了支持模板可以使用(也就是上述resize的缺省參數(shù)的寫法;很好的解決模板初始化問(wèn)題)//int* p = int*();//指針類型不支持直接把匿名對(duì)象給給指針類型Function<int>();Function<int*>();Function<double>();}void test_my_vector4(){wwx2::my_vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(10);for (auto e : v){cout << e << " ";}cout << endl;}void test_my_vector5(){wwx2::my_vector<int> v;v.push_back(1);//切記push_back也是會(huì)調(diào)用擴(kuò)容函數(shù)的v.push_back(2);v.push_back(3);v.push_back(4);//此時(shí)就很神奇的會(huì)涉及到,insert是否擴(kuò)容問(wèn)題,如果數(shù)據(jù)是在push_back的過(guò)程,insert就不涉及擴(kuò)容,如果,insert涉及擴(kuò)容,那么此時(shí)就有迭代器失效的問(wèn)題,本質(zhì)就是地址不連續(xù)//v.insert(3, 30);//聰明的我,居然寫成了這樣,真的是函數(shù)都調(diào)不明白啊(但是也剛剛好,可以引出我們的find函數(shù))//當(dāng)然此時(shí)也不一定一定要使用find,因?yàn)榇藭r(shí)可以直接使用迭代器(充分表明我的不聰明)v.insert(v.begin(), 0);v.insert(v.end(), 6);v.insert(v.begin() + 3, 30);//充分表明迭代器是真的好用(促進(jìn)我們通過(guò)變量看地址的好習(xí)慣)auto pos = find(v.begin(), v.end(), 3);//此時(shí)就是把我的迭代器區(qū)間傳給了find函數(shù),這樣就可以使用find函數(shù)在迭代器區(qū)間中尋找3這個(gè)元素if (pos != v.end())//這里這樣寫的目的:主要是為了防止越界{pos = v.insert(pos, 30);//像這種一直插一直插這種,就會(huì)導(dǎo)致一個(gè)問(wèn)題(經(jīng)典的迭代器失效問(wèn)題),本質(zhì)就是:地址不連續(xù)了}//并且此時(shí)如果上述這樣寫,那么pos在內(nèi)存中的位置是不會(huì)改變的,但是由于insert因?yàn)閮?nèi)存不足開空間,導(dǎo)致start和finish的位置發(fā)生了改變,間接導(dǎo)致begin和end(迭代器)發(fā)生了改變,導(dǎo)致迭代器失效(*pos)++;//意思就是:拿更新后的pos地址中的元素加加一下(但是本質(zhì)上是想要在,3的地方加加,最后會(huì)變成在30的地方加加),原因就是pos指向的那個(gè)地址是不變(但是地址中的數(shù)據(jù)在挪動(dòng)),并且此時(shí)因?yàn)閕nsert中的pos是個(gè)形參,所以不會(huì)影響我們外部的pos,所以此時(shí)最好使用返回值,直接把pos返回給我們//并且此時(shí)由于使用引用返回需要有臨時(shí)變量(常屬性),所以不推薦使用,所以這邊,我們是通過(guò)返回值的方式解決這個(gè)問(wèn)題的//總:pos失效后,我們都不推薦使用(*pos)++;所以不敢這樣寫for (auto e : v)//迭代器一失效(也就是begin和end的地址發(fā)生了改變),那么此時(shí)就會(huì)導(dǎo)致pos地址雖然不改變(但是它指向的空間發(fā)生了改變(從原來(lái)的begin和end的地址變成了一塊未知的地址(因?yàn)閎egin和end已經(jīng)因?yàn)閿U(kuò)容擁有了新地址,并且把原來(lái)的地址給釋放了))),所以pos指向的地址就是一個(gè)未知地址,此時(shí)pos指針就是一個(gè)野指針{//總:開空間之后,導(dǎo)致pos指向的迭代器地址被釋放,導(dǎo)致野指針問(wèn)題(這也就是第一種經(jīng)典的迭代器失效問(wèn)題)cout << e << " ";//所以明白了原理之后,此時(shí)的解決方法就是:更新一下pos指針指向的空間(依據(jù)pos和start的相對(duì)位置不改變來(lái)更新)} cout << endl;}void test_my_vector6(){wwx2::my_vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4); v.push_back(5);auto pos = find(v.begin(), v.end(), 2);if (pos != v.end()){v.erase(pos);}(*pos)++;//此時(shí)這個(gè)不是解引用的意思,可以算是對(duì)*這個(gè)運(yùn)算符重載的意思(本質(zhì)上*的運(yùn)算符重載就是在獲取一下我想要的功能或者是數(shù)據(jù))for (auto e : v)//并且此時(shí)這種刪除之后再訪問(wèn)的方式是很不好的,因?yàn)槿绻凑誩rase代碼來(lái)說(shuō),刪除最后一個(gè)及時(shí)把finish的位置往前挪動(dòng)一個(gè),此時(shí)如果再去訪問(wèn)剛剛4的pos位置,就會(huì)導(dǎo)致對(duì)一個(gè)空地址解引用,此時(shí)就出問(wèn)題了{ //所以總的來(lái)說(shuō):刪除數(shù)據(jù)后,是不允許進(jìn)行數(shù)據(jù)訪問(wèn)的(并且此時(shí)數(shù)據(jù)刪除也是伴隨著迭代器失效的問(wèn)題的),因?yàn)槲恢藐P(guān)系發(fā)生了改變,也就是導(dǎo)致地址不連續(xù)(迭代器失效的本質(zhì))cout << e << " ";}cout << endl;}void test_my_vector7(){wwx2::my_vector<int> v;v.push_back(10);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(50);for (auto e : v){cout << e << " ";}cout << endl;//此時(shí)要求刪除所有的偶數(shù)//std::vector<int>::iterator it = v.begin();wwx2::my_vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);//此時(shí)因?yàn)槲覀円呀?jīng)通過(guò)返回值可以直接拿到it的位置了,所以就不需要每次都++,因?yàn)閿?shù)據(jù)覆蓋之后,我的it就已經(jīng)是被覆蓋成了新的數(shù)據(jù),此時(shí)只要再判斷一下這個(gè)數(shù)據(jù)是不是偶數(shù)就行}else//因?yàn)榭梢赃B續(xù)拿到it位置的數(shù)據(jù),所以it++只有在不是奇數(shù)的時(shí)候需要使用{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}void test_my_vector8(){//wwx2::my_vector<int> v(10, 5);//wwx2::my_vector<int> v(10u, 5);//解決方案一:在整形后面加個(gè)u,表示無(wú)符號(hào)的意思,本質(zhì)就是讓它去找那個(gè)無(wú)符號(hào)的參數(shù)匹配wwx2::my_vector<int> v(10u, 5);//解決方案二:就是把上面那個(gè)函數(shù)提供一個(gè)int類型的重載函數(shù)(這個(gè)似乎有點(diǎn)傻傻的樣子)//迭代器構(gòu)造函數(shù)的正確使用方法:wwx2::my_vector<int> v2(v.begin(), v.end());//wwx2::my_vector<int> v(++v.begin(), --v.end());//此時(shí)這個(gè)一開始報(bào)錯(cuò)的原因(也就是不讓我加加減減的原因)就是:涉及臨時(shí)變量(常屬性問(wèn)題)//因?yàn)槲覀円婚_始的時(shí)候?qū)懙腷egin和end函數(shù)使用的是傳值返回(解決方法就是:使用傳引用返回,但是沒(méi)什么必要(避免風(fēng)險(xiǎn),導(dǎo)致first和last被間接改變))wwx2::my_vector<int> v3(v.begin() + 1, v.end() - 1);//避免臨時(shí)變量常屬性問(wèn)題 ,先返回,返回之后再加加減減//因?yàn)槲覀兊臉?gòu)造函數(shù)是使用隨機(jī)迭代器實(shí)現(xiàn)的,所以是可以接收任何類型的迭代器的,例如:std::string s1("hello world");wwx2::my_vector<int> v4(s1.begin(), s1.end());//所以傳什么類型的迭代器都是沒(méi)什么問(wèn)題的(迭代器就是牛),只要類型匹配就行(可以強(qiáng)轉(zhuǎn))//或者可以這樣玩(本質(zhì)就是在玩地址)int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//隨機(jī)迭代器,愛(ài)咋玩咋玩wwx2::my_vector<int> v5(arr, arr + 10);for (auto e : v){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}cout << endl;for (auto e : v3){cout << e << " ";}cout << endl;for (auto e : v4){cout << e << " ";}cout << endl;for (auto e : v5){cout << e << " ";}cout << endl;}void test_my_vector9(){int arr[] = { 0,10,4,3,2,6,9,8,1,7,5 };my_vector<int> v(arr, arr + 10);for (auto e : v){cout << e << " ";}cout << endl;cout << "排序之后的情況:" << endl;sort(v.begin(), v.end());//總的來(lái)說(shuō):就是算法庫(kù)里面存在著一個(gè)迭代器形式的sort函數(shù)(反正迭代器就是神),本質(zhì):指針(地址)yydsfor (auto e : v){cout << e << " ";}cout << endl;sort(arr, arr + sizeof(arr) / sizeof(arr[0]));//總歸有了迭代器,函數(shù)變得更加的好用了,更加方便了(可愛(ài)!),并且此時(shí)是 默認(rèn)是升序(降序需要控制一下)for (auto e : v){cout << e << " ";}//排降序的寫法cout << "降序:" << endl;//greater<int> g;//這個(gè)東西叫仿函數(shù)(具體以后學(xué)習(xí))//sort(arr, arr + sizeof(arr) / sizeof(arr[0]),g);//想要排降序,就需要多傳一個(gè)參數(shù),具體原理不了解,先看看怎么使用就行//這種寫法,很適合直接寫成匿名對(duì)象的形式sort(arr, arr + sizeof(arr) / sizeof(arr[0]), greater<int>());for (auto e : v){cout << e << " ";}}//此時(shí)這邊有一個(gè)很重要的知識(shí)點(diǎn):我們使用sort,排序的是我們自己的容器(vector),原理是因?yàn)槲覀儼祟^文件,去調(diào)用了別的頭文件中的函數(shù),這里好像埋了一個(gè)炸彈沒(méi)有解決void test_my_vector10(){my_vector<int> v(10u, 5);//調(diào)用自己實(shí)現(xiàn)的構(gòu)造函數(shù)for (auto e : v){cout << e << " ";}cout << endl;my_vector<int> v1(v);//調(diào)用拷貝構(gòu)造(本質(zhì)還是在調(diào)用構(gòu)造函數(shù),只是此時(shí)是通過(guò)this指針,用v這個(gè)已經(jīng)初始化的對(duì)象去初始化v1這個(gè)對(duì)象而已),注意和賦值的區(qū)別,區(qū)別就是賦值是兩個(gè)都已經(jīng)實(shí)例化的對(duì)象,而拷貝構(gòu)造是一個(gè)已經(jīng)實(shí)例化,一個(gè)還沒(méi)有for (auto e : v1){cout << e << " ";}cout << endl;my_vector<std::string> v2(3, "1111111111111111");for (auto e : v2){cout << e << " ";}cout << endl;my_vector<std::string> v3(v2);//這句代碼的意思就是使用一個(gè)string類的vector模板類來(lái)拷貝構(gòu)造另一個(gè)新對(duì)象(v2)//此時(shí)因?yàn)槭褂胿2去初始化v3的時(shí)候回去調(diào)用reserve函數(shù)(防止空間太大太小問(wèn)題),都是直接開空間,然后memcpy,最后delete原空間//這樣寫的好處有兩點(diǎn):一個(gè)是解決深淺拷貝問(wèn)題(前提是內(nèi)置類型),一個(gè)就是解決空間浪費(fèi)和不足問(wèn)題//但是此時(shí)如上述一樣,我們不再是內(nèi)置類型,而是自定義類型,并且此時(shí)這個(gè)自定義類型中也涉及到了深淺拷貝問(wèn)題(就是也有一塊空間)//那么此時(shí)就是變成是深深拷貝問(wèn)題,需要進(jìn)行兩次的開辟空間//所以如上述我們這樣寫,只調(diào)用了一次reserve(new)函數(shù),那么就會(huì)導(dǎo)致, 原本應(yīng)該有兩次的深拷貝變成了一次,就又會(huì)導(dǎo)致同一塊空間被析構(gòu)兩次的問(wèn)題了for (auto e : v3){cout << e << " ";}cout << endl;//所以此時(shí)我們按照這個(gè)寫法,我們就可以發(fā)現(xiàn),我們的程序因?yàn)橥粔K空間釋放了兩次而導(dǎo)致崩潰了//本質(zhì)的原因:就是我們使用了memcpy,它只會(huì)進(jìn)行淺拷貝,把原空間中的地址拷貝到新空間中,不會(huì)進(jìn)行深拷貝//所以解決的方法就是不能使用memcpy,而是自己再去實(shí)現(xiàn)一個(gè)深拷貝出來(lái)(因?yàn)閙emcpy是庫(kù)里面規(guī)定的寫法(不會(huì)進(jìn)行深拷貝))//所以memcpy只有在進(jìn)行內(nèi)置類型深拷貝的時(shí)候可以使用,而在拷貝自定義類型的時(shí)候,最好就不使用memcpy函數(shù)//解決原理是上述所說(shuō)的那樣,但是因?yàn)槲覀円呀?jīng)實(shí)現(xiàn)了一個(gè)深拷貝了,模板類中的自定義類型的數(shù)據(jù)的深拷貝問(wèn)題,我們是摸不到的,所以,此時(shí)我們并不能自己去實(shí)現(xiàn)深拷貝,(例:string類中的私有對(duì)象我們是訪問(wèn)不了的)//此時(shí)根據(jù)這個(gè)拷貝構(gòu)造的問(wèn)題,此時(shí)我們就還可以發(fā)現(xiàn),我們?cè)跀U(kuò)容的時(shí)候,復(fù)制數(shù)據(jù)的時(shí)候,使用的也是memcpy函數(shù)//所以擴(kuò)容(使用memcpy)對(duì)于普通的內(nèi)置類型處理是沒(méi)有什么問(wèn)題的,但是如果是自定義類型,那么此時(shí)就連擴(kuò)容本質(zhì)上也是有問(wèn)題的(因?yàn)閿U(kuò)容也是需要把舊空間中的數(shù)據(jù)拷貝到新空間的)// 并且由于擴(kuò)容的時(shí)候,會(huì)把原來(lái)的空間釋放掉(那么就會(huì)導(dǎo)致你的空間中所有的自定義類型上的指針類型,都是野指針)//所以同理,無(wú)論是擴(kuò)容還是構(gòu)造函數(shù),只要需要對(duì)自定義類型進(jìn)行拷貝,那么此時(shí)就不僅要涉及到外部空間的深拷貝,還要注意到空間內(nèi)的數(shù)據(jù)的深拷貝問(wèn)題//所以解決方法和拷貝構(gòu)造函數(shù)是一樣的,就是使用賦值運(yùn)算符重載,然后通過(guò)它間接的再去調(diào)用一次拷貝構(gòu)造(例:string類中的私有對(duì)象我們是訪問(wèn)不了的)//但是此時(shí)由于不是所有的類都會(huì)去重載賦值,string有重載賦值,但是vector類卻沒(méi)有重載賦值,所以此時(shí)導(dǎo)致vector類中類此時(shí)就算是使用了賦值運(yùn)算符重載//也不可以進(jìn)行深深拷貝問(wèn)題,還是解決不了問(wèn)題,還是一個(gè)深層次的淺拷貝問(wèn)題,所以還是會(huì)崩潰(string可以,但vector類不可以)//本質(zhì)上還是沒(méi)有兩次的深拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)(沒(méi)有重載賦值運(yùn)算符)//并且此時(shí)我們是要注意到,我們的構(gòu)造函數(shù)是可以使用現(xiàn)代化的寫法的} } int main() {wwx::vector<int>::iterator it;//cout << typeid(it).name() << endl;//typeid函數(shù)就是為了獲得這個(gè)變量的類型是什么而已wwx2::test_my_vector1();//測(cè)試尾插wwx2::test_my_vector2();//測(cè)試尾刪wwx2::test_my_vector3();//測(cè)試匿名對(duì)象wwx2::test_my_vector4();//測(cè)試resizewwx2::test_my_vector5();//測(cè)試insert和erase(本質(zhì):擴(kuò)容導(dǎo)致迭代器失效問(wèn)題)wwx2::test_my_vector6();//測(cè)試插入函數(shù)中迭代器失效wwx2::test_my_vector7();//測(cè)試編譯器對(duì)erase的控制(std是直接報(bào)錯(cuò)(只要?jiǎng)h除了數(shù)據(jù),就是報(bào)錯(cuò)))wwx2::test_my_vector8();//測(cè)試構(gòu)造函數(shù)wwx2::test_my_vector9();//測(cè)試隨機(jī)迭代器wwx2::test_my_vector10();//測(cè)試深淺拷貝問(wèn)題return 0; }代碼注釋都比較的詳細(xì)
總結(jié):星期五就該發(fā)的文章留到了今天,充分表明,擺爛,我也是專業(yè)的。
總結(jié)
以上是生活随笔為你收集整理的Learning C++ No.14【STL No.4】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C语言task的用法,C# Task 用
- 下一篇: 解决 “ISO C++ 不允许比较指针和