迭代器适配器
http://blog.csdn.net/effective_coder/article/details/8733853
在不斷的演變中,STL的愛(ài)好者擴(kuò)充了迭代器的內(nèi)容,他們?cè)诘鞯幕A(chǔ)上發(fā)展而來(lái),叫迭代器適配器,他提供了更多的操作功能,也不僅僅局限于容器,還可以應(yīng)用于更多方面。
首先看看迭代器適配器的分支圖:
?
以上的迭代器都叫做迭代器適配器,正如容器有標(biāo)準(zhǔn)容器和容器適配器,仿函數(shù)有標(biāo)準(zhǔn)仿函數(shù)和仿函數(shù)適配器,這里的迭代器適配器也是一樣的道理。顯然他們都是在原有迭代器的基礎(chǔ)之上發(fā)展而來(lái)的,所以基礎(chǔ)迭代器擁有的他們都擁有,包括上一節(jié)所講的幾個(gè)重要迭代器函數(shù)。下面我們將要一一的來(lái)講解上圖中的迭代器適配器。
1:逆向迭代器
逆向迭代器是一種適配器,他通過(guò)重新定義遞增遞減運(yùn)算符使其行為恰好相反。這樣一來(lái)使用這種迭代器算法將會(huì)逆向次序進(jìn)行。
定義方式:
Vector<int>::reserve_iterator?rit;
而且首位置為rbegin(),也就是原來(lái)的末位,末位置為rend(),也就是原來(lái)的首位;
請(qǐng)看下面一段代碼:
vector<int>?bec;
for(int?i=1;i<11;i++)
vec.push_back(i);
for_each(vec.rbegin(),vec.rend(),print);
//這里假定print為已經(jīng)定義的輸出函數(shù)
這樣輸出結(jié)果可想而知,輸出的當(dāng)然是10開(kāi)始的逆序。
請(qǐng)注意看接下來(lái)的例子,他對(duì)你理解逆向迭代器至關(guān)重要。
?
結(jié)果:
?
這就奇怪了,同樣是pos所指的位置,該位置為5,為什么利用逆向迭代器輸出來(lái)以后就變成4了?現(xiàn)在我們需要討論一個(gè)問(wèn)題,從輸出中我們知道結(jié)果已經(jīng)變了,但是到底是迭代器所指的位置變了,還是迭代器的位置沒(méi)變,而是邏輯位置發(fā)生了改變。這里讀者可以自己猜一下。
接下來(lái),廢話不多說(shuō),直接上圖!!!
?
有了這圖我就不需要再說(shuō)什么了,相信大家已經(jīng)對(duì)逆向迭代器理解了.下面我們將要介紹一個(gè)STL算法庫(kù)中針對(duì)逆向迭代器的函數(shù)。
Base()函數(shù)
該函數(shù)將逆向迭代器轉(zhuǎn)回正常的迭代器。在上面一個(gè)例子中已經(jīng)用到了。結(jié)果也已經(jīng)列出,不在多說(shuō)。
對(duì)于逆向迭代器,就這些主要點(diǎn)的內(nèi)容,改迭代器主要用來(lái)逆向輸出或者操作,只在一些特定的地方可以更好的發(fā)揮,但是也要掌握好他的用法,有時(shí)候處理起來(lái)還是比較方便。
2:輸入流輸出流迭代器
1:輸出流迭代器
輸出流迭代器也是一種適配器,他由輸出迭代器演變而來(lái),賦予了寫(xiě)入到輸出流中的能力,對(duì)于輸入輸出流這兩個(gè)迭代器,我認(rèn)為最好的方式就是通過(guò)實(shí)例來(lái)說(shuō)明問(wèn)題,可以更好的學(xué)到用法。
輸出流迭代器定義:
Ostream_iterator<type>(ostream,delim);
或Ostream_iterator<type>(ostream,);
上面ostream代表需要為他的構(gòu)造函數(shù)提供一個(gè)輸出流對(duì)象,我們一般是用cout,delim是一個(gè)字符串指針,表示以它的內(nèi)容來(lái)隔開(kāi)輸出的內(nèi)容。
Iter++?和++iter?:表示迭代器往前移動(dòng),對(duì)下一個(gè)流單位進(jìn)行寫(xiě)入。
下面直接看這個(gè)例子。
?
?
可以看到利用輸出流迭代器輸出單個(gè)元素或者是輸出整個(gè)容器都是十分方便的,其中的copy函數(shù)是把begin和end之間的部分復(fù)制到inWriter中,實(shí)際就是復(fù)制到輸出流中,所以整個(gè)容器都輸出來(lái)了。這種方式在容器中是最常用的方法。
2:輸入流迭代器
對(duì)于輸入流迭代器,就是利用算法讀取輸入流中的數(shù)據(jù),輸入輸出天生就是一對(duì)拍檔,但是輸入流卻要比輸出流復(fù)雜一點(diǎn),因?yàn)樽x取出來(lái)本來(lái)就要比寫(xiě)入進(jìn)去復(fù)雜。
定義:
利用構(gòu)造函數(shù)構(gòu)造一個(gè)輸入流迭代器的時(shí)候也需要傳遞一個(gè)輸入流對(duì)象作為參數(shù),我們使用cin進(jìn)行讀取,但是讀取動(dòng)作可能發(fā)生的錯(cuò)誤:讀取數(shù)據(jù)失敗或者是讀到了文件的尾部,因此我們利用了一個(gè)end_of_stream迭代器,他可以由istream_iterator的默認(rèn)構(gòu)造函數(shù)生成。
Istream_iterator:?????istream_iterator<type>?inRead(cin);
End_of_stream:??????istream_iterator<type>?inReadEOF;
只要輸入流迭代器有任何一次讀取失敗,他就會(huì)變成end_of_stream迭代器,所以每次讀取你都應(yīng)該把他們兩個(gè)拿來(lái)比較一番。
還有個(gè)值得說(shuō)明的是,輸入流迭代器的構(gòu)造函數(shù)一旦構(gòu)造他,就會(huì)馬上打開(kāi)輸入流緩沖區(qū),有時(shí)候會(huì)在構(gòu)造之后馬上讀取一個(gè)元素,所以盡量不要過(guò)早的定義它,有可能導(dǎo)致第一個(gè)元素?zé)o法傳回。當(dāng)然有些版本中會(huì)延緩這個(gè)動(dòng)作,不會(huì)馬上讀取,這個(gè)作個(gè)了解就好。真要出現(xiàn)了我們也無(wú)法解決。
下面直接看例子:
?
可以看到,輸入的是那幾個(gè)數(shù)字只出現(xiàn)了前面幾個(gè),那是因?yàn)槲覀儤?gòu)造函數(shù)傳遞的類(lèi)型參數(shù)是int?所以她讀取到字符的時(shí)候?qū)е伦x取錯(cuò)誤,迭代器變?yōu)?span style="font-family:'Times New Roman'">end_of_stream迭代器,循環(huán)結(jié)束。
對(duì)于輸入流輸出流迭代器,希望大家多用,多熟悉,本節(jié)只是提及了一下最基本的,并不深入,但是你會(huì)發(fā)現(xiàn)處理很多問(wèn)題還是很方便的,在以后有專(zhuān)門(mén)的章節(jié)介紹stream的那些知識(shí)。
3:安插型迭代器
Insert?迭代器用來(lái)將賦值和復(fù)制操作轉(zhuǎn)化為安插操作,(至于這句話是什么意思,我來(lái)分析一下,因?yàn)槿萜鞯牟僮鞫际琴x值和復(fù)制操作,都會(huì)產(chǎn)生臨時(shí)對(duì)象,所以效率不高,利用安插型迭代器直接插入一個(gè)值,效率會(huì)更好,而且在某些方面,不僅僅是效率問(wèn)題了。這就是安插型迭代器的理念。)
在介紹安插型迭代器之前,我們來(lái)看看copy算法的源代碼:
?
(只是模擬的,也許細(xì)節(jié)有出入,大概就這樣)
可以看到,copy從算法起點(diǎn)開(kāi)始不斷循環(huán),不斷賦值給to_pos,直到循環(huán)結(jié)束。于是有初學(xué)者直到了copy算法之后就開(kāi)始這樣使用,代碼如下:
?
?
結(jié)果大家可以猜想一下,這里我直接貼出來(lái):
有經(jīng)驗(yàn)的一看就是內(nèi)存錯(cuò)誤,也許是越界咯!
那么到底是什么原因勒?我們知道copy算法是依次賦值,我相信只要學(xué)過(guò)編程的都知道,要想給一個(gè)變量賦值,首先那個(gè)變量得有地址吧!要分配空間吧,不能給一個(gè)不存在的變量賦值吧,那么在這里,a容器使用默認(rèn)構(gòu)造函數(shù),構(gòu)造的是一個(gè)空容器,不存在任何長(zhǎng)度,也就沒(méi)分配那么多空間,如何存儲(chǔ)得下b的元素,失敗是必然的。
這里順便提一句,?在標(biāo)準(zhǔn)的C++算法庫(kù)中,沒(méi)有任何一個(gè)算法在不借助外來(lái)幫助的情況下可以改變?nèi)萜鞯拇笮?#xff0c;注意我說(shuō)的是算法庫(kù)中,不是指push_back這一類(lèi)容器自帶的函數(shù)。
所以在這里,我們的安插型迭代器出現(xiàn)用途了,這就是上面所說(shuō)的借助的外來(lái)幫助,安插性容器本來(lái)自帶了分配內(nèi)存并且插入的功能
改寫(xiě)后的程序,代碼如下:
在代碼中我只是修改了其中一個(gè)地方,?利用了后插迭代器的便捷函數(shù),也許大家還對(duì)安插迭代器陌生,前面這一切只是個(gè)鋪墊,下面我們真正的開(kāi)始介紹安插迭代器。
安插性迭代器分類(lèi):
1:前插迭代器。(默認(rèn)為只在最前面插入)
2:后插迭代器。(默認(rèn)為只能在最后插入)
3:插入迭代器(也就是可以指出插入位置的迭代器)
實(shí)際上他們都是調(diào)用相應(yīng)容器的插入函數(shù)。
每一種迭代器都可以由一個(gè)便捷函數(shù)加以生成和初始化(便捷函數(shù)不陌生吧,pair模版和make_pair函數(shù))
請(qǐng)記住下面這個(gè)表:
?
| 名稱(chēng) | 迭代器類(lèi)名?class | 調(diào)用相應(yīng)的函數(shù) | 便捷函數(shù) |
| 后插迭代器 | back_insert_iterator | Push_back(value) | Back_inserter |
| 前插迭代器 | front_insert_iterator | Push_front(value) | Front_inserter |
| 插入迭代器 | Insert_iterator | Insert(pos,value) | Inserter |
?
對(duì)于迭代器的舉例,這里我只列出后插的即可,代碼如下:
?
?
?
從這個(gè)程序中我們可以看到,后插迭代器的初始化,首先需要指明容器類(lèi)型,然后還要賦一個(gè)具體的容器,使他們綁定在一起,初始化方法需要掌握。接下來(lái)利用的是便捷函數(shù)back_inserter的用法,可以看出他比較方便,最后一段代碼表示利用copy算法把本身前面的一段插入到后面一段,但是也許有人不明白,為什么最后一個(gè)數(shù)值出錯(cuò)了勒?大家可以考慮一下這個(gè)原因是什么,上面一個(gè)例子我已經(jīng)說(shuō)了,安插迭代器可以在不分配內(nèi)存的情況下直接插入,所以這里只是錯(cuò)誤,但不至于程序崩潰。在對(duì)容器自身進(jìn)行插入時(shí)最好是分配好足夠的空間,因?yàn)檫@樣可以使原有的迭代器固定下來(lái),執(zhí)行插入也不容易出錯(cuò)。如果不固定容器大小則他的迭代器會(huì)經(jīng)常改變,這也就是導(dǎo)致錯(cuò)誤的原因。
解決辦法,在上面的代碼中加入這一行,我相信大家都知道加在哪:
coll.reserve(2*coll.size());?//把容器長(zhǎng)度重置為原來(lái)的兩倍。
?
?
?
安插型迭代器本身的內(nèi)容就不多,把前面的理解了就可以了,至于更高級(jí)的用法,這需要與算法庫(kù)中的函數(shù)結(jié)合才能發(fā)揮出效果。
迭代器適配器就到這里,我們主要分析了三種適配器的用法和注意點(diǎn),合理的運(yùn)用適配器會(huì)使程序更加方便簡(jiǎn)潔,本節(jié)我略去了幾個(gè)知識(shí),一個(gè)是為迭代器編寫(xiě)泛型函數(shù),一個(gè)是使用自定義的迭代器,這些過(guò)于高級(jí),我自己也一知半解,所以不能誤人子弟,以后有機(jī)會(huì)我會(huì)補(bǔ)充出來(lái)的。
總結(jié)
- 上一篇: Android显示横幅样式通知
- 下一篇: 尼尔机器人技能快捷键_《尼尔:机械部队》