C++ 向量擦除迭代器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4645705/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Vector erase iterator
提问by hidayat
I have this code:
我有这个代码:
int main()
{
vector<int> res;
res.push_back(1);
vector<int>::iterator it = res.begin();
for( ; it != res.end(); it++)
{
it = res.erase(it);
//if(it == res.end())
// return 0;
}
}
"A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the vector end if the operation erased the last element in the sequence."
“一个随机访问迭代器,指向由函数调用擦除的最后一个元素之后的元素的新位置,如果操作擦除了序列中的最后一个元素,则该位置是向量结束。”
This code crashes, but if I use the if(it == res.end())
portion and then return, it works. How come? Does the for loop cache the res.end()
so the not equal operator fails?
此代码崩溃,但如果我使用该if(it == res.end())
部分然后返回,它可以工作。怎么来的?for 循环是否缓存 the res.end()
so not equal 运算符失败?
回答by Pieter
res.erase(it)
always returns the next valid iterator, if you erase the last element it will point to .end()
res.erase(it)
总是返回下一个有效的迭代器,如果你删除它指向的最后一个元素 .end()
At the end of the loop ++it
is always called, so you increment .end()
which is not allowed.
在循环结束时++it
总是被调用,所以你增加.end()
这是不允许的。
Simply checking for .end()
still leaves a bug though, as you always skip an element on every iteration (it
gets 'incremented' by the return from .erase()
, and then again by the loop)
简单地检查.end()
仍然会留下一个错误,因为你总是在每次迭代时跳过一个元素(it
通过 from 返回“递增” .erase()
,然后再次通过循环)
You probably want something like:
你可能想要这样的东西:
while (it != res.end()) {
it = res.erase(it);
}
to erase each element
擦除每个元素
(for completeness: I assume this is a simplified example, if you simply want every element gone without having to perform an operation on it (e.g. delete) you should simply call res.clear()
)
(为了完整性:我假设这是一个简化的例子,如果你只是想让每个元素都消失而不必对其执行操作(例如删除),你应该简单地调用res.clear()
)
When you only conditionally erase elements, you probably want something like
当您仅有条件地擦除元素时,您可能需要类似
for ( ; it != res.end(); ) {
if (condition) {
it = res.erase(it);
} else {
++it;
}
}
回答by crazylammer
for( ; it != res.end();)
{
it = res.erase(it);
}
or, more general:
或者,更一般的:
for( ; it != res.end();)
{
if (smth)
it = res.erase(it);
else
++it;
}
回答by Jayhello
Because the method erase in vector return the next iterator of the passed iterator.
因为 vector 中的方法 erase 返回传递的迭代器的下一个迭代器。
I will give example of how to remove element in vector when iterating.
我将举例说明如何在迭代时删除向量中的元素。
void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 1
for(auto it = vecInt.begin();it != vecInt.end();){
if(*it % 2){// remove all the odds
it = vecInt.erase(it); // note it will = next(it) after erase
} else{
++it;
}
}
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
// recreate vecInt, and use method 2
vecInt = {0, 1, 2, 3, 4, 5};
//method 2
for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
if (*it % 2){
it = vecInt.erase(it);
}else{
++it;
}
}
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
// recreate vecInt, and use method 3
vecInt = {0, 1, 2, 3, 4, 5};
//method 3
vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
[](const int a){return a % 2;}),
vecInt.end());
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}
output aw below:
输出aw如下:
024
024
024
A more generate method:
更多的生成方法:
template<class Container, class F>
void erase_where(Container& c, F&& f)
{
c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
c.end());
}
void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 4
auto is_odd = [](int x){return x % 2;};
erase_where(vecInt, is_odd);
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}
回答by Niki Dimitrov
Something that you can do with modern C++ is using "std::remove_if" and lambda expression;
使用现代 C++ 可以做的事情是使用“std::remove_if”和 lambda 表达式;
This code will remove "3" of the vector
此代码将删除向量的“3”
vector<int> vec {1,2,3,4,5,6};
vec.erase(std::remove_if(begin(vec),end(vec),[](int elem){return (elem == 3);}), end(vec));
回答by Patrice Bernassola
The it++ instruction is done at the end of the block. So if your are erasing the last element, then you try to increment the iterator that is pointing to an empty collection.
it++ 指令在块的末尾完成。因此,如果您要擦除最后一个元素,则尝试增加指向空集合的迭代器。
回答by kbjorklu
You increment it
past the end of the (empty) container in the for loop's loop expression.
您递增it
超过 for 循环的循环表达式中(空)容器的末尾。
回答by Benoit
Do not erase and then increment the iterator. No need to increment, if your vector has an odd (or even, I don't know) number of elements you will miss the end of the vector.
不要擦除然后增加迭代器。无需增加,如果您的向量具有奇数(或偶数,我不知道)元素数,您将错过向量的末尾。
回答by Joseph Petroske
As a modification to crazylammer's answer, I often use:
作为对 crazylammer 答案的修改,我经常使用:
your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
your_vector_type::iterator curr = it++;
if (something)
res.erase(curr);
}
The advantage of this is that you don't have to worry about forgetting to increment your iterator, making it less bug prone when you have complex logic. Inside the loop, curr will never be equal to res.end(), and it will be at the next element regardless of if you erase it from your vector.
这样做的好处是你不必担心忘记增加迭代器,当你有复杂的逻辑时,它更不容易出错。在循环内部,curr 永远不会等于 res.end(),并且无论您是否从向量中删除它,它都将位于下一个元素。
回答by Skippy le Grand Gourou
The following also seems to work?:
以下似乎也有效?:
for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
res.erase(it--);
}
Not sure if there's any flaw in this??
不知道这个有没有漏洞??
回答by Dawoon Yi
if(allPlayers.empty() == false) {
for(int i = allPlayers.size() - 1; i >= 0; i--)
{
if(allPlayers.at(i).getpMoney() <= 0)
allPlayers.erase(allPlayers.at(i));
}
}
This works for me. And Don't need to think about indexes have already erased.
这对我有用。并且不需要考虑索引已经擦除。