如何在C ++中擦除vector中的条目?

时间:2010-09-05 04:51:34

标签: c++ windows vector

我基本上循环遍历所有条目以检查是否要删除某些条目,但似乎是错误的方式:

std::vector<HANDLE> myvector; 
for(unsigned int i = 0; i < myvector.size(); i++)
{
    if(...)
         myvector.erase(myvector.begin()+i);
}

有人发现了问题吗?如何正确地做到这一点?

4 个答案:

答案 0 :(得分:8)

您可以使用std::remove_if。这会将所有剩余元素移到前面,并将迭代器返回到新的后面。然后你可以删除它:

struct my_predicate
{
    bool operator()(HANDLE) const
    {
        return ...;
    }
};

typedef std::vector<HANDLE> vector_type;

vector_type::iterator newEnd =
    std::remove_if(myvector.begin(), myvector.end(), my_predicate());

myvector.erase(newEnd, myvector.end());

通常在一条线上完成。如果你的编译器支持lambda(C ++ 0x),你可以这样做:

vector_type::iterator newEnd =
    std::remove_if(myvector.begin(), myvector.end(), [](HANDLE){ return ... });

myvector.erase(newEnd, myvector.end());

将谓词保持为本地。


如果你觉得这很难看,那就把它包起来:

template <typename Vec, typename Pred>
Pred erase_if(Vec& pVec, Pred pPred)
{
    pVec.erase(std::remove_if(pVec.begin(), pVec.end(),
                                pPred), pVec.end());

    return pPred;
}

然后:

erase_if(myvector, mypredicate);
当然,

C ++ 0x lambda的工作原理相同。

答案 1 :(得分:4)

你的问题是算法。如果两个相邻元素符合您的删除标准会发生什么?第一个将被删除,但因为i在循环的每次迭代后递增,所以将跳过第二个。这是因为向量在内存中是连续的,删除后的所有元素都会向前移动一个索引。

丑陋的黑客将会做以下事情:

std::vector<HANDLE> myvector; 
for(unsigned int i = 0; i < myvector.size();)
{
    if(...)
         myvector.erase(myvector.begin()+i);
    else
         i++;
}

我不确定使用迭代器是否可行,因为调用erase会使擦除元素之后的元素的迭代器失效。

优雅的解决方案是使用std::remove_if,正如GMan所建议的那样。这将抽象出两件事:

  1. 您的搬迁条件
  2. 移除容器元素的过程
  3. 编辑:我还应补充一点,在最坏的情况下,被攻击的解决方案是 O(n 2 。假设你的移除条件是 O(1),GMan的解决方案是 O(n)。我强烈建议您学习并使用GMan的解决方案。

答案 2 :(得分:1)

也许是另一个hacky解决方案......

std::vector<HANDLE> myvector; 
for(unsigned int i = myvector.size()-1; i >=0; --i)
{
    if(...)
         myvector.erase(myvector.begin()+i);
}

但至少它很简单。

答案 3 :(得分:0)

你应该使用向量迭代器, AND ,删除时,为迭代器分配erase()返回的值

for (it = myvector.begin(); it != myvector.end();) {
    if (...) {
        it = myvector.erase(it);
        continue;
    }

    ++it;
}