Removing Item from Vector While Iterating

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



Leave a reply



Submit