web-dev-qa-db-ja.com

反復中にベクターからアイテムを削除しますか?

アクティブまたは非アクティブのアイテムを保持するベクターがあります。パフォーマンスの問題のためにこのベクターのサイズを小さくしたいので、非アクティブとしてマークされたアイテムをベクターから消去したいです。繰り返しながらこれを試しましたが、「vector iterators incompatible」というエラーが表示されます。

vector<Orb>::iterator i = orbsList.begin();

    while(i != orbsList.end()) {
        bool isActive = (*i).active;

        if(!isActive) {
            orbsList.erase(i++);
        }
        else {
            // do something with *i
            ++i;
        }
    }
49
Lucas

過去にこれを行った最も読みやすい方法は、std::vector::erase と組み合わせ std::remove_if。以下の例では、この組み合わせを使用して、ベクトルから10未満の数値を削除します。

非c ++ 0xの場合、以下のラムダを独自の述語に置き換えることができます:

// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));

// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(), 
                       [](int i) { return i < 10; }), v.end());
62
Moo-Juice

Wilxの答えに同意します。実装は次のとおりです。

// curFiles is: vector < string > curFiles;

vector< string >::iterator it = curFiles.begin();

while(it != curFiles.end()) {

    if(aConditionIsMet) {

        it = curFiles.erase(it);
    }
    else ++it;
}
45
Vassilis

それはできますが、while()を少しシャッフルする必要があると思います。 erase()関数は、消去された要素の次の要素iterator erase(iterator position);に反復子を返します。 23.1.1/7からの標準からの引用:

A.erase(q)から返される反復子は、要素が消去される前のqの直後の要素を指します。そのような要素が存在しない場合、a.end()が返されます。

ただし、代わりに Erase-removeイディオム を使用する必要があります。

15
wilx

誰かがインデックスで作業する必要がある場合

vector<int> vector;
for(int i=0;i<10;++i)vector.Push_back(i);

int size = vector.size();
for (int i = 0; i < size; ++i)
{
    assert(i > -1 && i < (int)vector.size());
    if(vector[i] % 3 == 0)
    {
        printf("Removing %d, %d\n",vector[i],i);
        vector.erase(vector.begin() + i);
    }

    if (size != (int)vector.size())
    {
        --i;
        size = vector.size();
        printf("Go back %d\n",size);
    }
}
4
Dawid Drozd

eraseは、次のイテレータ値へのポインタを返します(Vassilisと同じ):

vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{   if(condition)
        mit = myVec.erase(mit);
    else
        mit++;
}
2
Pierre

std::listの代わりにstd::vectorデータ構造用。消去とイテレーションを組み合わせた場合、使用する方が安全です(バグが少なくなります)。

2
Raedwald

彼らが言ったように、ベクターのイテレーターは、使用するイテレーター増分の形式に関係なく、vector::erase()で無効になります。代わりに整数インデックスを使用してください。

1

ベクターの中央からアイテムを削除すると、そのベクターのすべてのイテレーターが無効になるため、これを行うことはできません(pdate:Wilxの提案に頼らずに)。

また、パフォーマンスが心配な場合は、ベクターの途中からアイテムを消去するのはとにかく悪い考えです。おそらく、std::list

1