This loop changes the iterators while running:
std::vector<int> c;
c.push_back(1);
c.push_back(2);
std::vector<int>::iterator iter = c.begin();
std::vector<int>::iterator endIter = c.end();
while( iter != endIter )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
}
It does not work because:
Iterators and references to the erased elements and to the elements between them and the end of the container are invalidated. Past-the-end iterator is also invalidated
How can I rewrite this (without using std::list
, and using the while
loop) ?
By the way, I know that auto
has been implemented since C++11. Why would it be beneficial to use it ?
Simply do not cache the end iterator that will be invalidated:
while( iter != c.end() )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
}
or clear the vector after printing:
for(const auto& i : c) {
std::cout << i << std::endl;
}
c.clear();
Erasing an element changes end()
. Change the loop:
while( iter != c.end())
Either
Rewrite it as
while( iter != c.end() )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
}
and the code will no longer rely on any potentially invalidated iterators,
or
"Refresh" any potentially invalidated iterators after each invalidating operation
while( iter != endIter )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
endIter = c.end();
}
These are the two generic approaches typically used in cases like that.
A more idiomatic way of doing this...
while(c.begin() != c.end()) c.erase(c.begin());
Though this is very slow, as a vectors underlying implementation uses a contiguous array(with extra space on the end). So repeatedly erasing the begin element is very ineficient, as every element ends up getting copied one space in the array earlier, n - index times! You can jurastically increase performance by doing this:
while(c.begin() != c.end()) c.pop_back();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With