11

XCode4.6を使用してMacOSXでテストされています。

このサンプルコードは、std::list期待どおりに作品の最後の要素を削除することを示しています。へのイテレータ参照list::end()は「最後から1つ」であり、最後の要素を削除しても有効です。

しかし、2番目の例は私の直感に反しています。リストの最初の要素を削除すると、「最初から1つ過ぎた」と思った変更が変更されます。list::rend()

私の期待は間違っていましたか?なぜそれが間違っていたのですか?最後の要素を削除して「最後から1つ」への参照が有効なままであるのに(そうではないのですか?)、.rend()前の要素を削除すると「先頭()の前の1」への参照が無効になるのはなぜですか?

void printList( list<int>& os )
{
  for( int& i : os )
    printf( "%d ", i ) ;
  puts("");
}

void testList()
{
  list< int > os ;
  os.push_back( 1 ) ;
  os.push_back( 2 ) ;
  os.push_back( 3 ) ;
  os.push_back( 4 ) ;
  os.push_back( 5 ) ;  

  // Forward iterators:  reference to .end() not invalidated when remove last elt.
  list<int>::iterator fwdEnd = os.end() ;
  printList( os ) ;
  os.erase( --os.end() ) ; // remove the 5 (last elt)
  printList( os ) ;
  if( fwdEnd == os.end() )  puts( "YES, fwdEnd==os.end() still, iterators not invalidated" ) ;  // I get __this__ result
  else puts( "NO: fwdEnd INVALIDATED" ) ;



  list<int>::reverse_iterator revEnd = os.rend() ;
  // remove the front element
  printList( os ) ;
  os.erase( os.begin() ) ; // removes the 1
  printList( os ) ;
  if( revEnd == os.rend() )  puts( "YES revEnd is still valid" ) ;
  else  puts( "NO: revEnd NOT valid" ) ; // I get __this__ result
}
4

1 に答える 1

23

これは、逆イテレータの参照ロジックが通常のイテレータとはわずかに異なるためです。要素を指しますが、逆参照されると、前の要素への参照が生成されます。

次のことを試してみると、これが簡単にわかります。

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    vector<int> v = { 1, 2, 3, 4, 5, 6 };
    auto i = find(begin(v), end(v), 3);
    cout << *i << endl;

    vector<int>::const_reverse_iterator ri(i);
    cout << *ri << endl;
}

出力は次のようになります。

3
2

逆イテレータが物理的に特定の要素を指す場合、論理的にはその前の要素を指します。したがって、インデックスを持つコレクション内の要素を物理的に指す逆イテレータは、逆i参照されると、インデックスを持つ要素(への参照)を生成しますi-1

                       i, *i
                       |
    -      1     2     3     4     5     6     -
                 |     | 
                 *ri   ri

rend()これが、イテレータが実際にコレクション内の最初の要素を指しているのであって、最初の要素の前の要素を指しているのではない理由です。したがって、最初の要素を削除すると無効になります。

           begin, *begin                       end, *end
           |                                   |
    -      1     2     3     4     5     6     -
    |      |                             |     |
*rend      rend                    *rbegin     rbegin

これはリストだけでなく、双方向イテレータを提供するすべてのコレクションに適用されます。

于 2013-02-07T20:23:38.190 に答える