4

I am trying to remove some items from a string list in c++. The code compiles successfully but at runtime it gives "Segmentation fault (core dumped)" error. I have abstracted the code as follows.

#include <iostream>
#include <list>
using namespace std;

int main()
{
    //a string list
    list<string> entries;

    //add some entries into the list
    entries.push_back("one");
    entries.push_back("two");
    entries.push_back("three");
    entries.push_back("four");

    //pass over the list and delete a matched entry
    list<string>::iterator i = entries.begin();
    while(i != entries.end())
    {
        if(*i=="two")
            entries.erase(i);   // *** this line causes the error ***
        i++;
    }

    //print the result
    for(const string &entry : entries)
        cout<<entry<<"\n";
    return 0;
}
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
Sys Soft
  • 161
  • 4
  • 16
  • 2
    Think about what happens to the iterator `i` when you erase it from the list. Is the iterator really valid after that? I recommend [this `erase` reference](https://en.cppreference.com/w/cpp/container/list/erase), please note what it *returns*. – Some programmer dude May 19 '20 at 08:19
  • 1
    `erase` returns the iterator. Do `if() { i=erase} else {i++}` – manuell May 19 '20 at 08:19
  • Does this answer your question? [Can you remove elements from a std::list while iterating through it?](https://stackoverflow.com/questions/596162/can-you-remove-elements-from-a-stdlist-while-iterating-through-it) – manuell May 19 '20 at 08:23

3 Answers3

5

std::list<T,Allocator>::erase invalidates the iterator to the erased element, i.e. i. After that the operation like i++ leads to UB.

You can assign it to the return value of erase, which is iterator following the removed element.

while(i != entries.end())
{
    if(*i=="two")
        i = entries.erase(i);
    else
        i++;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
1

Erased iterators are invalidated. For your convenience, list::erase returns next past erased:

if(*i == "two") i = list.erase(i);
else ++i;
bipll
  • 11,747
  • 1
  • 18
  • 32
1

you can just "remove" the element, no need for iterators, but if you use it, then be aware that erase invalidates the iterator..

#include <iostream>
#include <list>

int main ()
{
  //a string list
    std::list<std::string> entries;

    //add some entries into the list
    entries.push_back("one");
    entries.push_back("two");
    entries.push_back("three");
    entries.push_back("four");
    entries.push_back("two");

    entries.remove("two");
    std::cout<<entries.size() << std::endl;

  return 0;
}
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97