vector削除操作eraseメソッドの注意事項


vectorの使用は非常に便利で、任意のタイプのデータ構造を保存することができます.オブジェクトポインタなどをvectorに格納したり、要素を削除したりするときに、対応するメモリを解放する必要があります.
本稿では主にerase法,特に循環体におけるerase法の使用について述べ,隠性の問題があるかどうかに注意する必要がある.
eraseの関数プロトタイプには2つの形式があります.
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
例えばクラスAがあり、
class A
{
public:
    int id;
    A(void);
    ~A(void);
};
定義vector vec
for (int i=0; i<10; i++)
{
    A *p = new A();
    p->id = i;
    vec.push_back(p);
}
次にvecのidが5の要素を削除します.
for(vector::iterator iter=vec.begin(); iter!=vec.end(); iter++)
{
    if(5 == (*iter)->id)
    {
        delete *iter;
        veci.erase(iter);
    }
}
このコードを初めて見ると問題はありませんが、実際には大きな問題があります.eraseメソッドを呼び出すと、iterは野ポインタになり、iter++をループし続けるとエラーになります.
コードを変更し続けます.
for(vector::iterator iter=vec.begin(); iter!=vec.end(); iter++)
{
    if(5 == (*iter)->id)
   {
        delete *iter;
        iter = veci.erase(iter);
    }
}
eraseの戻り値は、An iterator that designates the first element remaining beyond any elements removed,or a pointer to the end of the vector if no such element existsです.
上のコードをよく読むと、実際には問題があります.まず、コードは2つ連続して5の要素を削除することはできません.1つ目を削除した後、iterは2つ目を指し、増加した後、2つ目の後ろを指しています.次に、要素5がvectorの最後にある場合、削除後にiterが増加してもエラーが発生します.
では、正しい書き方は次のようになります.
for(vector::iterator iter=vec.begin(); iter!=vec.end(); )
{
    if(5 == (*iter)->id)
   {
        delete *iter;
        iter = veci.erase(iter);
    }
    else
    {
        iter++;
    }
}
これにより、同じ2つの要素が連続して存在する問題を解決し、同時に削除する要素を最後にすると、削除後、eraseはvector.end()を返すため、問題はありません.