Guru of the week:#18 迭代指標. (轉)

worldblog發表於2007-12-23
Guru of the week:#18 迭代指標. (轉)[@more@]

/*此文是譯者出於自娛翻譯的GotW(Guru of the Week)系列文章的一篇,原文的版權是屬於Hub Sutter(著名的C++專家,《Exceptional C++》的作者)。此文的翻譯沒有徵得原作者的同意,只供學習討論。——譯者:黃森堂*/

#18 迭代指標.

難度:7/10

任何在使用標準庫都知道使用公共與非公共iterator容易犯錯誤,你發現了多少種呢?

問題:

以下程式至少有四處關於iterator的問題,你發現多少呢?

int main( int, char*[] ) { vector e; copy( istream_iterator( cin ), istream_iterator(), back_inserter( e ) ); vector::iterator first = find( e.begin(), e.end(), "01/01/95" ); vector::iterator last = find( e.begin(), e.end(), "12/31/95" ); *last = "12/30/95"; copy( first, last, ostream_iterator( cout, "n" ) ); e.insert( --e.end(), TodaysDate() ); copy( first, last, ostream_iterator( cout, "n" ) ); }


解決方法:

以下程式至少有四處關於iterator的問題,你發現多少呢?

int main( int, char*[] ) { vector e; copy( istream_iterator( cin ), istream_iterator(), back_inserter( e ) );


到這兒是好的,Date類過載了運算子>>( istream&, Date& )來提供抽取功能,Date類用istream_iterator從cin流中讀取Date資料,copy演算法僅僅填充Date資料到vector.

vector::iterator first = find( e.begin(), e.end(), "01/01/95" ); vector::iterator last = find( e.begin(), e.end(), "12/31/95" ); *last = "12/30/95";


錯誤:這兒是的,原為last指標可能指向e.end,因此這不是一個有新效的間接引用的iterator

find演算法需要兩個引數,如果值沒有找到,在這情況裡,如果"12/31/95"不在e裡面,那麼last是等於e.end(),它指向越過容器的底,且是無效的iterator.

copy( first, last, ostream_iterator( cout, "n" ) );


錯誤:這兒是非法的,原因first指標實際上在last之後。

如果"01/01/95"在 e裡面不找到,但"12/31/95"找到了,那麼迭代品last將指向在集合裡的物件(Date物件等於"12/31/95"),但first指向end,然而,copy需要first指向第一個在物件集合的物件,同樣last是相似的,[first, last]必須是有效的範圍。

除非你使用標準庫的版本,或許問題在除錯階段中找到。

e.insert( --e.end(), TodaysDate() );


錯誤:"--e.end()"是不合法的。

這個理由簡單,vector::iterator是簡單的Date*,且你不允許去修改內建型別的臨時物件,例如,以下是很明顯示是非常程式碼:

Date* f(); // 返回Date* p = --f(); // error, but could be "f() - 1"


幸虧的是,這兒沒有損失:

e.insert( e.end() - 1, TodaysDate() );


錯誤:這兒仍然有其它錯誤...,如果e是空的,e.end()-1是無效的iterator.

copy( first, last, ostream_iterator( cout, "n" ) ); }


錯誤:first與last不是有效的iterator

當你在插入物件到vector的任何時候,它不是重新分配緩衝,而是在塊中進行追加,然而,有時vector可能滿了,此時增加物件將觸發重新分配,這兒,例如當插入操作返回結果,vector可能需要或不需要重新分配,如果它沒有這樣做,在我們已存在的iterator與copy中可能是無效的。

總結:

當你使用iterator時,這兒有四點注意:

1.有效的值:間接引用的iterator是有效嗎?,例如,"*e.end()"總是邏輯錯誤的。

2.有效的生存期:當你開始使用iterator時候它還仍然有效嗎?,當我們獲得了經過若干操作後它還有效嗎?

3.有效的範圍:成對的iterator是否是有效的範圍呢?,first是在last之前嗎?兩者是否都指向相同的容器裡面嗎?

4.非法操作內建型別:例如:在"--e.end()"上面修改內建型別的臨時物件(幸運的是,在你的程式碼中將捕捉到這種錯誤與類的iterator型別,庫的作者允許這種經常在排序任何物件的語法的轉換).


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-995470/,如需轉載,請註明出處,否則將追究法律責任。

相關文章