我基本上循环遍历所有条目以检查是否要删除某些条目,但似乎是错误的方式:
std::vector<HANDLE> myvector;
for(unsigned int i = 0; i < myvector.size(); i++)
{
if(...)
myvector.erase(myvector.begin()+i);
}
有人发现了问题吗?如何正确地做到这一点?
答案 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所建议的那样。这将抽象出两件事:
编辑:我还应补充一点,在最坏的情况下,被攻击的解决方案是 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;
}