3

私の理解では、連想コンテナーのイテレーターは、挿入または消去中に無効化されません (イテレーターが指すノードが消去されない限り)。しかし、以下のプログラムでは、挿入によってイテレータが無効になっているようです。私の理解は間違っていますか?

typedef std::set<unsigned int> myset_t;

int main(int argc, char **argv)
{
    myset_t rs;
    myset_t::reverse_iterator rit;
    myset_t::reverse_iterator srit;
    int ii = 500;

    rs.insert(10);
    rs.insert(11);
    rs.insert(12);
    rs.insert(13);
    rs.insert(14);
    rs.insert(100000);
    rs.insert(102000);
    rs.insert(103000);

    rit = rs.rbegin();

    while(rit != rs.rend()) {
        srit = rit;
        if (*rit < 100000) {
            cout << "bailing here " << *rit << endl;
            return 0;
        } 
        rit++;
        cout << "Before erase " << *rit << endl;
        rs.erase(*srit);
        cout << "Before insert " << *rit << endl;
        rs.insert(ii);
        cout << "After insert " << *rit << endl;
        ii++;
    }
    cout << "Out of loop" << endl;
}
===

The output is 
Before erase 102000
Before insert 102000
After insert 14
bailing here 14

=====
4

1 に答える 1

10

標準コンテナーの反復子の約束された動作は、そのコンテナーの逆反復子には当てはまりません。

逆方向反復子は、逆参照時に逆方向反復子が参照する要素のに来る通常の (順方向に移動する) 反復子をメンバーとして実際に格納します。次に、逆イテレータを逆参照すると、基本的に、この保存された通常のイテレータのコピーがデクリメントされ、それが逆参照されます。だからこれは問題です:

rit = rs.rbegin();     // rit stores rs.end()
srit = rit;            // srit also stores rs.end()
rit++;                 // rit stores a normal iterator pointing to the last element

rs.erase(*srit);       // this deletes the last element, invalidating the normal
                       // iterator which is stored in rit. Funnily enough, the
                       // one stored in srit remains valid, but now *srit is a
                       // different value

「開始前」反復子がないため、逆反復子はこのように動作します。実際に参照する要素に反復子を格納すると、何がrs.rend()格納されるでしょうか? これを回避する方法があると確信していますが、標準化委員会が望んでいない妥協が必要だったと思います。あるいは、彼らはこの問題をまったく考慮していなかったか、十分に重要だと考えていなかったのかもしれません。

于 2013-11-07T01:46:20.037 に答える