5

C ++仕様(23.2.4.3)によると、vector :: Erase()は、「消去の時点以降のすべてのイテレータと参照」のみを無効にします。

そのため、reverse_iteratorsを使用してすべてのベクターメンバーを渡す場合、現在のイテレーターを消去しても、rend()メンバーが無効になることはありません。

このコードはG++で実行されますが、Windows(VS2010)ではランタイム例外が発生します。

#include <vector>

using namespace std;

int main()
{
    vector<int> x;
    x.push_back(1);
    x.push_back(2);
    x.push_back(3);

    //Print
    for(vector<int>::const_iterator i = x.begin(); i != x.end(); ++i)
        printf("%d\n", *i);

    //Delete second node
    for(vector<int>::reverse_iterator r = x.rbegin(); r != x.rend(); ++r)
        if(*r == 2)
            x.erase((r+1).base());

    //Print
    for(vector<int>::const_iterator i = x.begin(); i != x.end(); ++i)
        printf("%d\n", *i);

    return 0;
}

エラーは興味深いです:

式:デクリメントできないベクトルイテレータ

2回目の実行時に2番目のforループの行に指定されます。デクリメントは、reverse_iteratorの内部の「現在の」イテレータメンバーを指します。これは、reverse_iteratorがインクリメントされるたびにデクリメントされます。

誰かがこの振る舞いを説明できますか?

ありがとう。

編集

このコードサンプルは、rの問題ではなく、rend()の問題であることをよりよく示していると思います。

//Delete second node
for(vector<int>::reverse_iterator r = x.rbegin(); r != x.rend();)
{
    vector<int>::reverse_iterator temp = r++;

    if(*temp == 2)
        x.erase((temp+1).base());
}

vector iterators incompatibleまた、消去後のエントリ時にforループでエラーが発生します。

4

5 に答える 5

4

プログラムは未定義動作を呼び出します。したがって、どちらのコンパイラも正しくありません。

標準によるとstd::vector<int>::reverse_iterator、はのtypedefですstd::reverse_iterator<std::vector<int>::iterator>。の実装はメンバーstd::reverse_iterator<Iter>を持つように指定され、他のすべてのメンバーと関数はメンバーの動作に基づいて指定されます。protectedIter current;reverse_iteratorcurrent

したがって、が有効であると仮定します。r == reverse_iterator(i)ここで、iは。への有効なイテレータですstd::vector<int> x;。これらのそれぞれは、標準によって保証されます。

r.current == i
(r+1).current == (i-1)
(r+1).base() == (i-1)

を呼び出すとx.erase((r+1).base());、以降のすべてのイテレータi-1が無効になります。もちろん、これにはi、、したがっても含まれr.currentます。

プログラムが次に評価しようとするのはです++r。この式は、効果があると指定されています--r.current;。ただし、r.currentが無効になっているため、この式は未定義動作です。です++r

于 2011-03-08T18:32:54.027 に答える
3

Areverse_iteratorは通常のイテレータの単なるラッパーであることが多いため、逆イテレータをインクリメントすると、おそらくその下のイテレータが1つ減ります。同様にrbegin、コンテナ内のすべての要素の後にあるイテレータを返すため、同じ方法で無効になります。

于 2011-03-08T17:34:49.217 に答える
2

これがあなたがやろうとしていることをするためのはるかに良い方法です:

struct CustomRemove
{
    bool operator()(int i)
    {
        return (i == 2);
    }
};

int main()
{
    std::vector<int> x;
    x.push_back(1);
    x.push_back(2);
    x.push_back(3);

    CustomRemove custom_remove;

    std::copy(x.begin(), x.end(), std::ostream_iterator<int>(std::cout, "\n"));
    x.erase(std::remove_if(x.begin(), x.end(), custom_remove), x.end());
    std::copy(x.begin(), x.end(), std::ostream_iterator<int>(std::cout, "\n"));

    return 0;
}
于 2011-03-08T17:58:18.767 に答える
1

reverse_iteratorは、通常のイテレータを現在の位置の後の位置に内部的に格納します。rend()はbegin()の前に何かを返す必要があるため、これを行う必要がありますが、これは不可能です。したがって、base()イテレータを誤って無効にすることになります。

于 2011-03-08T17:37:47.770 に答える
0

(r+1).base()と効果的に同じ要素を指しているのでr、消去(r+1).base()は実際には無効になりrます。ほとんどの場合、g ++は内部でポインターを使用するだけなので、すべてが正しく機能しているように見えます。

ベクトルから一致する要素を削除しようとしている場合は、removeまたはを使用するのがはるかに優れたアプローチですremove_if

于 2011-03-08T18:01:45.900 に答える