C++ 如何在C++;?

C++ 如何在C++;?,c++,windows,vector,C++,Windows,Vector,我基本上是循环检查所有条目,以检查是否要删除某些条目,但似乎以错误的方式: std::vector<HANDLE> myvector; for(unsigned int i = 0; i < myvector.size(); i++) { if(...) myvector.erase(myvector.begin()+i); } std::vector myvector; for(无符号整数i=0;i返回一个新的(有效)迭代器到被删除元素之后的下一

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

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

有人发现了其中的问题吗?如何正确操作?

您可以使用
std::remove\u(如果
)。这将把所有剩余的元素移到前面,并将迭代器返回到新的后面。然后可以删除它:

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());
保持谓词的局部性


如果你觉得这很难看,那就收起它:

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;
}

当然,C++0x lambda的工作是相同的。

您应该使用向量迭代器进行此操作,并且,在删除时,为迭代器分配由
erase()返回的值。


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

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

std::vector<HANDLE> myvector; 
for(unsigned int i = 0; i < myvector.size();)
{
    if(...)
         myvector.erase(myvector.begin()+i);
    else
         i++;
}
std::vector myvector;
for(无符号整数i=0;i
我不确定使用迭代器是否有效,因为调用
erase
会使迭代器对已擦除元素之后的元素无效

正如格曼所建议的,优雅的解决方案是使用。这将抽象出两件事:

  • 你的搬迁条件
  • 移除容器元素的过程

  • 编辑:我还应该补充一点,在最坏的情况下,被黑客攻击的解决方案是O(n2)。GMan的解决方案是O(n),假设您的移除条件是O(1)。我强烈鼓励您学习和使用GMan的解决方案。

    也许是另一个黑客解决方案

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

    但至少它很简单。

    这似乎是最简单的解决方案,但我不确定它是否真的有效?我猜删除条目后的一个条目将被
    it++
    跳过。这是一个轻微的错误,当if为真时,您不需要执行
    it++
    (否则,您可以跳过一个元素,或者更糟的是,您可以跳过
    end()
    。最好是这样:
    for(it=v.begin();it!=v.end();){如果(…)it=v.erase(it);else++it;}
    还值得注意的是,这在算法上很糟糕,因为
    erase
    将导致以下所有元素被删除“向下移动一个”remove\u if/erase习惯用法更好,因为它避免了这种情况。是的,都是真的。感谢您的评论。现在将添加“continue”,并向下移动增量。还可以将
    if(…)
    替换为
    while(…),只要条件还可以判断它是否在向量的末尾。我不太理解GMan的解决方案,所以我接受这个黑客版本。@用户:您应该请求澄清和/或教你C++。BTW:<代码> EraseE.()/代码>返回一个新的(有效)迭代器到被删除元素之后的下一个元素。@sth我明白了,你是对的。Ivan编辑的解决方案使用了这个事实。
    
    for (it = myvector.begin(); it != myvector.end();) {
        if (...) {
            it = myvector.erase(it);
            continue;
        }
    
        ++it;
    }
    
    std::vector<HANDLE> myvector; 
    for(unsigned int i = 0; i < myvector.size();)
    {
        if(...)
             myvector.erase(myvector.begin()+i);
        else
             i++;
    }
    
    std::vector<HANDLE> myvector; 
    for(unsigned int i = myvector.size()-1; i >=0; --i)
    {
        if(...)
             myvector.erase(myvector.begin()+i);
    }