I want to erase list elements one by one. Before removing any of list elements I want to see the whole list.
#include <iostream>
#include <list>
int main()
{
std::list<int>numbers{0,1,2,3,4,5,6,7,8,9};
auto it=numbers.begin();
for(int i=0;i<10;i ){
for(auto j:numbers)
std::cout<<j<<" ";
std::cout<<std::endl;
it=numbers.erase(it);
it ;
}
return 0;
}
OUTPUT:
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 3 4 5 6 7 8 9
1 3 5 6 7 8 9
1 3 5 7 8 9
1 3 5 7 9
double free or corruption (out)
Why this process goes just to half of elements. How to delete all list elements one after another step by step? I know I could use numbers.clear()
, but I don't need that.
Also, why erasing doesn't go in order? (0 is deleted, then 2, and then 4)?
CodePudding user response:
The issue is with these two lines
it=numbers.erase(it);
it ;
The function, list::erase
, returns an iterator pointing to the element that followed the last element erased. Here, your code removes the item from the list and sets it
to the next element in the list. Then the instruction it
advances the iterator one more place, hence skipping one item in the list.
The simple solution is to comment out the it
line:
#include <iostream>
#include <list>
int main()
{
std::list<int>numbers{0,1,2,3,4,5,6,7,8,9};
auto it=numbers.begin();
for(int i=0;i<10;i )
{
for(auto j:numbers)
std::cout<<j<<" ";
std::cout<<std::endl;
it=numbers.erase(it);
//it ;
}
return 0;
}
This gives this output:
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9
4 5 6 7 8 9
5 6 7 8 9
6 7 8 9
7 8 9
8 9
9
CodePudding user response:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
template <typename Container>
void print(const Container& container, std::ostream& sout = std::cout) {
std::copy(std::begin(container), std::end(container),
std::ostream_iterator<typename Container::value_type>(sout, " "));
sout << '\n';
}
int main() {
std::list<int> numbers{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// Note that the update action is skipped
for (auto it = numbers.begin(); it != numbers.end();) {
print(numbers);
it = numbers.erase(it);
}
return 0;
}
This can be done exclusively with iterators. I moved the printing out to its own function. The key here is that the loop declaration is no longer responsible for updating the iterator, as it now happens in the body. Reading about std::list<T>::erase()
tells us that the function returns an iterator that points to the element after what was erased. Since we're erasing from the beginning, the act of erasing naturally moves through the whole list.
It's also important to note that the loop has to be done this way. Erasing from the list invalidates all pre-existing iterators of the list. The only valid one now is the iterator returned by the erase() function.
CodePudding user response:
it=numbers.erase(it);
it ;
In the first line the list removes the element the iterator points to and returns an iterator pointing at the next element. The old element does no longer exist and the it
passed to erase()
becomes invalid. That's why you have to use the returned iterator, which points to the next element.
The second line then skips that and the iterator no longer points at the start of the new list.
You are removing every second element from the list: erase, skip, erase, skip, erase, skip, ...