Hi I read in C primer that adding elements to a vector invalidates the iterators. I don't understand why deleting elements doesn't invalidate them as the following code works
std::vector<int> a = {1,2,3,4,5,6};
auto b = a.begin();
while (b != a.end()){
if (*b%2 != 0)
a.erase(b);
else
b ;
}
NOTE: This code if from C primer itself and cpp reference as well
CodePudding user response:
Not actually an answer to the question, but I think it is worth mentioning that in modern C you should try to avoid iterators by using algorithms and range-based for loops. In this particular case use std::erase_if
:
std::vector<int> a = {1,2,3,4,5,6};
std::erase_if(a, [](int x) { return x%2 != 0; });
CodePudding user response:
In general this code snippet
auto b = a.begin();
while (b != a.end()){
if (*b%2 != 0)
a.erase(b);
else
b ;
}
is invalid. It works because the container std::vector satisfies the concept of contiguous ranges. If instead of the vector you will use for example std::list<int>
when the iterator b
will be invalid.
It would be correctly to write
auto b = a.begin();
while (b != a.end()){
if (*b%2 != 0)
b = a.erase(b);
else
b ;
}
CodePudding user response:
Common idiom. From cppreference: (erase) 'Invalidates iterators and references at or after the point of the erase, including the end() iterator.
Others have pointed out it should be written like this:
#include <vector>
std::vector<int> vec = { 1, 2, 3, 4 };
for (auto it = vec.begin(); it != vec.end(); )
{
if (*it % 2 != 0)
{
it = vec.erase(it);
}
else
{
it;
}
}
Adjust if one prefers 'while' over 'for'. If performance is paramount one can start from the end though this may be less cache friendly.
Edit: code snippet is literally the cppreference link.
CodePudding user response:
Adding elements to a vector may lead to a complete reallocation of the vector. This invalidates all iterators held previously.
If you delete an entry of the vector the erase method returns: a) a iterator to the next valid element b) the end iterator.
But you have to use it. In your case:
b = a.erase(b);