在學習STL中關於迭代器reverse_iterator轉換,發現個有趣的問題,如下例子。#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> col1;
for (int i=1;i<=9;++i)
col1.push_back(i);
vector<int>::iterator pos;
pos= find(col1.begin(),col1.end(),5);
cout<<"pos:"<<*pos<<endl;
vector<int>::reverse_iterator rpos(pos);
cout<<"rpor:"<<*rpos<<endl;
system("pause");
return 0;
}
輸出的結果是:
Pos:5
Rpos:4
若將
pos= find(col1.begin(),col1.end(),5);
改為
pos= find(col1.begin(),col1.end(),3);
輸出的結果是:
Pos:3
Rpos:2
rpos總是指向pos的前一個值,為什麼呢?候捷先生譯的《C++標準模板庫》裡是這麼解釋的:“注意,這不是bug,這是特性!導致這個行為的原因是區間的半開性。為了能夠指定容器內所有元素,我們必須運用‘最後一個元素的下一位置’。”“逆向迭代器的設計者運用了一個小技巧:他們實際上倒置了‘半開原則’”
這兩句話非常重要,首先容器的區間是左閉右開的,區間是以一個空位置作為區間的結束。對於逆向迭代器言,這個空位置就成了開始rbegin()的位置。但是這個位置上是沒有值的,因此rbegin的值就取的是該位置前的一個值。--這正是“運用的小技巧”。這個小技巧保持了“以一個空位置作為區間結束”的原則。
說到轉換,逆向迭代器用正向迭代器初始化,在轉化過程中調用的是逆向迭代器的構造器,看下逆向迭代器的構造器的實現代碼。註:代碼在檔案<xutility>中能找到(VC++8.0)。
explicit __CLR_OR_THIS_CALL reverse_iterator(_RanIt _Right)
: current(_Right)
{ // construct wrapped iterator from _Right
}
有關_RanIt和current的聲明和定義如下:
typedef _RanIt iterator_type;
protected:
_RanIt current; // the wrapped iterator
};
從代碼可以看出其實current是一個迭代器變數,在轉換中它指向的正是正向迭代器。再來看看operator *的實現代碼。
reference __CLR_OR_THIS_CALL operator*() const
{ // return designated value
_RanIt _Tmp = current;
return (*--_Tmp);
}
因此,從代碼中可以知道,轉換後逆向迭代器的實際位置(代碼中的current)與正向迭代器的實際位置是保持一致的,而由於逆向迭代器在取值時迭代器位置向前減了1,即(*--_Tmp)。
書上有這樣的譯者註解:“‘將一個迭代器轉化為逆向迭代器的過程中保持(履行)的是實際位置(元素)而非邏輯位置(數值)’,這句話的意思是,當pos轉換為rpos,它們指向同一個實際地點,但它們所代表的意義(或說所代表的邏輯位置或數值)卻變得不同了。”。從逆向迭代器的實現來看,書中所指的“實際位置”或“實際地點”,就是current。問題的原因結果就如表表。