C++反復器の'逆反復器'


逆反復器(Reverse Iterator)は、通常の反復器のアダプタであり、要素を逆順序で巡回する目的で、自己増加および自己減少操作を再定義します.通常の反復器の代わりに標準アルゴリズムライブラリで逆反復器を使用する場合、実行結果は通常の場合とは逆になります.それ以外に,その用法は通常の反復器と全く同様であり,詳細には議論しない.
ここで主に論じたのは,逆反復器の特殊で誤りやすい性質,すなわちその「論理位置」と「物理位置」である.まず、例を見てから始めましょう.
vector<int> vec;
for(vector<int>::size_type i=1; i<10; ++i)
{
	vec.push_back(i);
}

vector<int>::iterator itr = vec.begin()+4;
cout<<*itr<<endl;
vector<int>::reverse_iterator r_itr(itr);
cout<<*r_itr<<endl;

この例では、vecには1から9までの9つの連続数字が格納され、通常の反復器が数字5を指すように初期化され、印刷出力結果は5であることが明らかになった.次に、通常の反復器と同じ物理的な位置を指し、出力を印刷する逆反復器を初期化します.この場合、結果はいくらですか?
逆反復器という特殊な性質を知らないと、結果は同じ5だと勘違いしがちです.しかし、実際の状況はそうではなく、4、つまり前の位置の要素です!具体的な理由は、逆反復器の「物理的位置」と「論理的位置」の2つの概念に関連しています.
1つの容器の範囲は通常の反復器で「半開半閉」の区間として表されることはよく知られている.ヘッダはbeginで、コンテナの最初の要素の位置を指します.末尾はendで、最後の要素の次の位置を指し、各容器はこのような位置を提供しています.この位置は参照できませんが、合法的なアドレスです.逆に、最初の要素の位置の前の位置容器は、vectorやstringにとって不正な位置であるなどの保証はありません.ここでは「合法」と「不法」と言いますが、簡単に言えば、1つの合法的な位置は反復器にとって達成可能であり、最後の要素の次の位置end()のように考えられます.一方、最初の要素の前の位置では、反復器はそれを指すことができません.begin()-1という式は異常を引き起こします.従って、逆反復器と通常反復器は、rbegin()が通常反復器のend()位置に対応し、rend()がそのbegin()位置に対応する物理的位置で一対一の対応を保っている.
しかし、逆反復器を通常の反復器と概念的に一致させるためには、begin()(逆反復器はrbegin()に対応)が最初の要素(逆反復器にとって最後の要素である)に対応し、end()(逆反復器はrend()に対応)が最後の要素の次の位置に対応するそこで、標準ライブラリの設計者たちは、逆反復器の論理的位置が物理的位置の前の位置に等しいという方法を考え出した.すなわち、物理的位置はメモリ内の反復器の実際の位置に対応し、論理的位置は反復器がコンテナ内の要素の位置に対応する.このようにrbegin()にとって、その物理的位置は、コンテナの最後の要素の次の位置であり、論理的位置、すなわち、コンテナの最後の要素の位置(逆反復器にとって最初の要素の位置)であり、同じrend()物理的位置は、コンテナの最初の要素の位置、論理的位置、すなわち最初の位置の前の位置(依然として参照不可)である.このように,逆反復器は通常の反復器と一致する概念,すなわち「半開半閉」区間を持つ.より直感的に以下の図を示します.
 
(「The C++Standard Library,A Tutorial And Reference」)
このように、冒頭の例では、逆反復器は、前の通常の反復器と同様の物理的位置(対応要素5)に初期化され、その論理的位置、すなわち前の位置は、解引用によって要素4が得る.