Seg fault przy itererowaniu stringa, funkcja erase.

0

Mam taki sobie kod, i główkuje dlaczego dostaje seg faulta. Z tego jak rozumiem dokumentacje SV powinien być tutaj niemożliwy. Kolejny raz mi sie to już zdarza, wcześniej po prostu użyłem innej metody; ale chciałbym w końcu zrozumieć co jest nie tak.

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
  int nLines;
  cin >> nLines;
  while(nLines--)
  {
    string line;
    cin >> line;
    // erase spaces and punctuations
    for(auto st = line.begin(); st != line.end(); st++)
    {
      if(*st == ' ' || *st == ',' || *st == '.')
      {
        st = line.erase(st);
      }
    }
    cout << line << endl;
  }
  return 0;
}
 

Funkcja erase według dokumentacji zwraca albo iterator wskazujacy na znak ktory jest obecnie w miejscu usunietego znaku albo string::end.
Wiec jeżeli st jest równe string::end to dereferencja iteratora nie powinna miec miejsca, kod powinien wyskoczyc z pętli. A jezeli st nie jest równe string::end to dereferencja iteratora nie powinna powodowac seg faulta.

To jest moje rozumienie tego jak działają te funkcje, i nie widze jak to jest możliwe, że mimo to dostaje seg fault. Ktoś może mi to wytłumaczyć?
Program wywala sie na lini:
st = line.erase(st);

Seg fault wystepuje dla inputu:

1
test, Test
4

Wykonujesz it++ na it równemu end(). Ogółem modyfikacja kontenera po którym iterujesz to zły pomysł.

Skorzystaj z idiomu erase/remove, najlepiej używając funkcji pomocniczej:

template<typename Container, typename Predicate>
void erase_if(Container& c, Predicate p)
{
	using std::begin;
	using std::end;
	using std::remove_if;

	auto realEnd = end(c);
	auto removedIt = remove_if(begin(c), realEnd, p);

	c.erase(removedIt, realEnd);
}

Wykorzystanie:

erase_if(line, [](char c){ return c == ' ' || c == '.' || c == ','; });

Jeśli nie chcesz/nie możesz tego zrobić, użyj tego bezpośrednio, ale uważaj na https://dev.krzaq.cc/post/an-erase-remove-idiom-gotcha/

1 użytkowników online, w tym zalogowanych: 0, gości: 1