如何在循环时从矢量中删除元素?

时间:2011-12-21 22:28:36

标签: c++

我循环遍历带有for(int i = 0; i < vec.size(); i++)等循环的向量。在这个循环中,我检查该向量索引处元素的条件,如果某个条件为真,我想删除该元素。

如何在循环过程中删除矢量元素而不会崩溃?

6 个答案:

答案 0 :(得分:31)

从STL容器中删除满足给定谓词的所有元素的惯用方法是使用remove-erase idiom。我的想法是将谓词(即为某个元素产生真或假的函数)移动到给定函数中,比如说pred然后:

static bool pred( const std::string &s ) {
  // ...
}

std::vector<std::string> v;
v.erase( std::remove_if( v.begin(), v.end(), pred ), v.end() );

如果你坚持使用索引,你不应该为每个元素增加索引,而只是为那些没有被删除的元素增加:

std::vector<std::string>::size_type i = 0;
while ( i < v.size() ) {
    if ( shouldBeRemoved( v[i] ) ) {
        v.erase( v.begin() + i );
    } else {
        ++i;
    }
}

然而,这不仅仅是更多的代码而且更少惯用(读取:C ++程序员实际上必须查看代码,而'擦除和删除'成语立即给出了一些想法,但也效率低得多)向量将它们的元素存储在一个连续的内存块中,因此擦除除向量末尾之外的位置也会在段擦除后将所有元素移动到新的位置。

答案 1 :(得分:9)

如果你不能使用删除/删除(例如因为你不想使用lambdas或写一个谓词),请使用标准习语来删除序列容器元素:

for (auto it = v.cbegin(); it != v.cend() /* not hoisted */; /* no increment */)
{
    if (delete_condition)
    {
        it = v.erase(it);
    }
    else
    {
        ++it;
    }
}

如果可能的话,更喜欢删除/删除:

#include <algorithm>

v.erase(std::remove_if(v.begin(), v.end(),
                       [](T const & x) -> bool { /* decide */ }),
        v.end());

答案 2 :(得分:8)

使用Erase-Remove Idiom,使用带有谓词的remove_if来指定您的条件。

答案 3 :(得分:3)

if(vector_name.empty() == false) {
    for(int i = vector_name.size() - 1; i >= 0; i--)
    {
        if(condition) 
            vector_name.erase(vector_name.at(i));
    }
}

这对我有用。并且不需要考虑索引已经删除。

答案 4 :(得分:1)

向后迭代向量。这样,你就无法获得你尚未访问过的元素的能力。

答案 5 :(得分:1)

我意识到你具体要求从vector中删除,但只想指出从std :: vector中删除项目的成本很高,因为删除项目之后的所有项目都必须复制到新位置。如果要从容器中删除项目,则应使用std :: list。 std :: list :: erase(item)方法甚至返回指向刚擦除后的值的迭代器,因此很容易在for或while循环中使用。使用std :: list也很好用的是指向非擦除项的迭代器在整个列表存在期间仍然有效。例如,参见docs at cplusplus.com

那就是说,如果你别无选择,一个可行的技巧就是创建一个新的空向量并从第一个向量中添加项目,然后使用std :: swap(oldVec,newVec),这是非常的高效(没有副本,只是更改内部指针)。