迭代时从向量中删除项目?

时间:2011-01-17 12:27:46

标签: c++ stl iterator

我有一个包含活动或非活动项目的向量。我希望此向量的大小对于性能问题保持较小,因此我希望从向量中删除已标记为非活动的项目。我在迭代时尝试这样做但是我收到错误“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;
        }
    }

8 个答案:

答案 0 :(得分:61)

我过去最可读的方法是使用std::vector::erasestd::remove_if结合使用。在下面的示例中,我使用此组合从矢量中删除任何小于10的数字。

对于非c ++ 0x,你可以用你自己的谓词替换下面的lambda:

// 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());

答案 1 :(得分:45)

我同意wilx的回答。这是一个实现:

// curFiles is: vector < string > curFiles;

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

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

    if(aConditionIsMet) {

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

答案 2 :(得分:15)

你可以这样做,但我认为你必须重新调整你的while()erase()函数返回删除后的元素的迭代器:iterator erase(iterator position);。引自23.1.1 / 7的标准:

  

从a.erase(q)返回的迭代器   立即指向元素   在元素之前的q之后   擦除。如果不存在这样的元素,   返回a.end()。

虽然您可能应该使用Erase-remove idiom代替。

答案 3 :(得分:4)

如果有人需要处理索引

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 :(得分:2)

您可能需要考虑为数据结构使用std::list而不是std::vector。在将擦除与迭代相结合时使用它更安全(不易出错)。

答案 5 :(得分:1)

从向量中间删除项目将使该向量的所有迭代器无效,因此您无法执行此操作(更新:不依赖于Wilx的建议)。

另外,如果你担心性能,那么从矢量中间删除项目无论如何都是个坏主意。也许您想使用std::list

答案 6 :(得分:1)

正如他们所说的那样,无论你使用哪种形式的迭代器增量,vector的迭代器都会在vector::erase()上失效。改为使用整数索引。

答案 7 :(得分:1)

erase返回指向下一个迭代器值的指针(与Vassilis相同):

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