C++ how to erase from vector while iterating
erase
returns next iterator.
if ((*a) == 2)
{
delete a;
it = intList.erase(it);
}
EDIT:remove()
and remove_if()
will copy the elements(pointer here) and one will end up with multiple elements pointing to same integer and if you then try to free them, you'll be left with dangling pointers.
Consider the vector has 4
elements which look something like
0x196c160 0x196bec0 0x196c180 0x196bee0
One might be tempted to use erase-remove
idiom
auto temp = remove_if(vec.begin(),vec.end(),[](const auto &i){return *i==2;});
Now it looks like
0x144aec0 0x144b180 0x144b180 0x144aee0
temp
would be pointing to 3rd
element and a
for(auto it=temp;it!=vec.end();it++)
delete *it;
Now the second element is a dangling pointer.
EDIT 2:
The above problem could be solved if you delete
before the element is copied.Look at @Dietmar's answer.
How to erase or change element while iterating over vector in C++?
Instead of erasing elements in the middle of the vector, you should write the results from the beginning of the vector and eliminate the unused elements in the end of vector.
int finalSize = 0;
for(int i = 0; i < N; i++)
{
if(result[i] != 0) {
result[finalSize++] = i;
}
}
result.resize(finalSize);
Erase element in vector while iterating the same vector
In the line:
it2 = uc.erase(it2);
an element pointed by iterator it2
is removed from the vector, elements are shifted in memory in order to fill that gap which invalidates it2
. it2
gets a new value and now points to the first element after the the removed one or the end of the vector (if removed element was the last one). This means that after erasing an element you should not advance it2
. An alternative to proposed remove-erase idiom
is a simple trick:
for(it2 = uc.begin(); it2 != uc.end();)
{
...
if(...)
{
it2 = uc.erase(it2);
}
else
{
++it2;
}
...
}
You can read more about this here.
Edit:
Regarding your comment, you can use a flag to pass the information whether an element has been erased or not, and you can check it when you get out from the inner loop:
for(it2=uc.begin(); it2 != uc.end();)
{
bool bErased = false;
for(it3 = c.begin(); it3 != c.end(); ++it3)
{
if(adjacencyMatris[(*it2).id][(*it3).id] == 0 )
{
B.id = (*it2).id;
it2 = uc.erase(it2);
bErased = true;
B.color = currentColor;
c.push_back(B);
break;
}
}
if(!bErased)
++it2;
}
After you've erased an element from uc
you need to break from the inner loop. In the next iteration of the outer loop you'll be able to access the next element in the uc
through a valid iterator.
Removing item from vector, while in C++11 range 'for' loop?
No, you can't. Range-based for
is for when you need to access each element of a container once.
You should use the normal for
loop or one of its cousins if you need to modify the container as you go along, access an element more than once, or otherwise iterate in a non-linear fashion through the container.
For example:
auto i = std::begin(inv);
while (i != std::end(inv)) {
// Do some stuff
if (blah)
i = inv.erase(i);
else
++i;
}
Deleting element while iterating through nested vectors
In your code, if there are multiple elements equal to 55, there would be multiple times of erase vector elements which will take much overhead to move elements.
A better solution is to follow erase-remove idiom to move all the qualified elements to the end of the vector, then erase them together in one time.
For example:
vector< vector<int> >::iterator row;
vector<int>::iterator col;
for (row = vvi.begin(); row != vvi.end(); row++) {
row->erase( std::remove( row->begin(), row->end(), 55), row->end());
}
std::remove will move all the element which equal to 55 to the end of the vector and return the iterator of the head of them.
row->erase(iterator1, iterator2) will erase all the elements between 2 iterators.
And you don't need to care iterator anymore.
Remove element from vector while iterating over it
Solution 1: using shift!
and push!
julia> I = Vector{String}(["first", "second", "third", "fourth", "fifth"]);
julia> Inew = Vector{String}(0);
julia> while !isempty(I)
i = shift!(I);
if i == "fourth"; println("Skipped $i");
else println("Got: i = $i"); push!(Inew, i);
end
end
Got: i = first
Got: i = second
Got: i = third
Skipped fourth
Got: i = fifth
julia> show(Inew)
String["first", "second", "third", "fifth"]
Solution 2: Using
splice!
julia> I = Vector{String}(["first", "second", "third", "fourth", "fifth"]);
julia> i = 1;
julia> while i <= length(I)
if I[i] == "fourth"; splice!(I,i);
else i += 1;
end
end
julia> show(I)
String["first", "second", "third", "fifth"]
However, note that this is not necessarily more efficient, since new memory is allocated for I
whenever you splice it anyway (since it's changing size).
Solution 3: using findin
and deleteat!
(i.e. "the one-liner"):
julia> I = Vector{String}(["first", "second", "third", "fourth", "fifth"]);
julia> deleteat!(I, findin(I, ["second", "fourth"]))
3-element Array{String,1}:
"first"
"third"
"fifth"
If you don't really need to perform any other intermediate actions (e.g. printing) and you just want to identify and delete elements, then this is probably the way to go.
Further ramblings:
Also, regarding your attempt to do this via a for loop: a cardinal rule when iterating with a for loop (in any language) is that the state of the variable that you're iterating over does not change. Disobeying this rule will usually lead to errors in the best case, or undefined behaviour and silent errors in the worst case. If the state of the variable is meant to change, then you're not looking at a 'for loop' iteration, but at the more general while loop which makes no assumption of consistent state.
I.e. what you've done here is the correct approach and you shouldn't be looking for one that involves a for loop. (and if you do happen to find one, consider that bad code and leave it alone :p ). But, yes, there were nicer-looking ways of doing it; however it's worth noting that what you did is basically re-discover the wheel, in that you made explicit the interface on which the for loop actually relies in julia. I.e. the following code:
for i in MyCollection; print("$i "); end
essentially gets internally translated as its equivalent:
state = start(MyCollection)
while !done( MyCollection, state)
(i, state) = next(MyCollection, state)
print("$i ")
end
Delete elements from a vector in C++11 while iterating over it
When you call
vec1.erase(itVec1);
you invalidate itVec1
. After that, ++itVec1
is not right. It leads to undefined behavior. You need to change your code a little bit.
for( ; itVec1 != vec1.end(); ) {
if (Oracle(*itVec1))
{
itVec1 = vec1.erase(itVec1);
}
else
{
++itVec1;
}
}
You can remove all the boiler plate code by using the Erase-Remove Idiom:
vec1.erase(std::remove_if(vec1.begin(), vec1.end(), Oracle), vec1.end());
Related Topics
Does the C++ Standard Allow For an Uninitialized Bool to Crash a Program
Does the Default Constructor Initialize Built-In Types
What Does the Restrict Keyword Mean in C++
How Well Is Unicode Supported in C++11
Are Inline Virtual Functions Really a Non-Sense
What Is the Point of Function Pointers
Does C++ Support Compile-Time Counters
Template Specialization VS Function Overloading
Sequence-Zip Function For C++11
Does C++ Support Variable Length Arrays
Can't Make Value Propagate Through Carry
How to Write a Large Buffer into a Binary File in C++, Fast
Examples of Good Gotos in C or C++
Can You Remove Elements from a Std::List While Iterating Through It
Combining C++ and C - How Does #Ifdef _Cplusplus Work
How Does Virtual Inheritance Solve the "Diamond" (Multiple Inheritance) Ambiguity
What Is the Purpose of the Most Vexing Parse
Difference Between Private and Protected Members of C++ Classes