程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 淺談reverse_iterator的base()函數

淺談reverse_iterator的base()函數

編輯:C++入門知識

非原創,原文鏈接:http://blog.csdn.net/shuchao/article/details/3705252

  調用reverse_iterator的base成員函數可以產生"對應的"iterator,但這句話有些辭不達意。舉個例子,看一下這段代碼,我們首先把從數字1-5放進一個vector中,然後產生一個指向3的reverse_iterator,並且通過reverse_iterator的base初始化一個iterator:

vector<int> v;
v.reserve(5);
for(int i = 1;i <= 5; ++ i) { // 向vector插入1到5
  v.push_back(i);
}
vector<int>::reverse_iterator ri = find(v.rbegin(), v.rend(), 3);
vector<int>::iterator i(ri.base()); // 使i和ri的base一樣

  執行上述代碼後,可以想到產生的結果就像這樣:

  這張圖很好,顯示了reverse_iterator和它對應的base iterator之間特有的偏移量,就像rbegin()和rend()與相關的begin()和end()一樣,但並沒有說出了所有你需要知道的東西。特別是,它並沒有解釋怎樣在ri上實現你在i上想要完成的操作。有些容器的成員函數只接受iterator類型的參數,所以如果你想要在ri所指的位置插入一個新元素,你不能直接這麼做,因為vector的insert函數不接受reverse_iterator。如果你想要刪除ri 所指位置上的元素也會有同樣的問題。erase成員函數會拒絕reverse_iterator,堅持要求iterator。為了完成刪除和一些形式的插入操作,你必須先通過base函數將reverse_iterator轉換成iterator,然後用iterator來完成工作。

  先讓我們假設你要在ri指出的位置上把一個新元素插入v。特別的,我們假設你要插入的值是99。記住ri在上圖中遍歷的順序是自右向左,而且插入操作會將新元素插入到ri位置,並且將原先ri位置的元素移到遍歷過程的"下一個"位置,我們認為3應該出現在99的左側。插入操作之後,v看起來像這樣:

  當然,我們不能用ri來指定插入的地方,因為它不是一個iterator。我們必須用i來代替。如上所述,當ri指向3時,i(就是ri.base())指向4。如果我們用ri來指定插入位置,那麼用i指向插入位置,那個假設就是正確的。結論呢?

  要實現在一個reverse_iterator ri指出的位置上插入新元素,在ri.base()指向的位置插入就行了。對於insert操作而言,ri和ri.base()是等價的,而且ri.base()真的是ri對應的iterator。現在再來考慮刪除元素的情況。回顧一下最初的vector(也就是在插入99之前)ri與i的關系:

  如果你要刪除ri指向的元素,你不能直接使用i了,因為i與ri不是指向同一個元素。因此,你要刪除的是i的前一個元素。要實現在一個reverse_iterator ri指出的位置上刪除元素,就應該刪除ri.base()的前一個元素。對於刪除操作而言,ri和ri.base()並不等價,而且ri.base()不是ri對應的iterator。我們還是有必要看看刪除操作的代碼,因為它還挺令人驚訝的。

vector<int> v;
 // 向v插入1到5,同上
vecot<int>::reverse_iterator ri =
find(v.rbegin(), v.rend(), 3); // 同上,ri指向3
v.erase(--ri.base()); // 嘗試刪除ri.base()前面的元素;對於vector,一般來說編譯不通過

  這個設計並不存在什麼問題。表達式--ri.base()確實能夠指出我們需要刪除的元素。而且,它們能夠處理除了vector和string之外的其他所有容器,它可能也能處理vector和string,但對於大多數vector和string的實現,它無法處理。在這樣的實現下,iterator(和const_iterator)會采用內建的指針來實現,所以ri.base()的結果是一個指針。C和C++都規定了不能直接修改函數返回的指針,所以在string和vector的迭代器是指針的STL平台上,像--ri.base()這樣的表達式無法通過編譯。要移植從一個由reverse_iterator指出的位置刪除元素時,你應該盡量避免修改base的返回值。沒問題。如果你不能減少調用base的返回值,只需要先增加reverse_iterator的值,然後再調用base。

 // 同上
v.erase((++ri).base()); // 刪除ri指向的元素;
// 這下編譯沒問題了!

  因為這個方法適用於所有的標准容器,這是刪除一個由reverse_iterator指出的元素時首選的技巧。

  現在已經很清楚了,reverse_iterator的base成員函數返回一個"對應的"iterator的說法並不准確。對於插入操作而言,的確如此;但是對於刪除操作,並非如此。當需要把reverse_iterator轉換成iterator的時候,有一點非常重要的是你必須知道你准備怎麼處理返回的iterator,因為只有這樣你才能決定你得到的iterator是否是你需要的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved