Wyrzuca bład po skompilowaniu "out of range"

Wyrzuca bład po skompilowaniu "out of range"
MI
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 8 lat
  • Postów:11
0

Witam serdecznie,
Dlaczego po skompilowaniu wyrzuca mi komunikat:
terminate called after throwing an instance of std::out of range.

kod funkcji:

Kopiuj
size_t dlugosc = tekst.size();
    for(int i=0;i<dlugosc-1;i++){
        if(tekst[i]==tekst[i+1]){
            tekst.erase(i,1);
        }
    }

pozdrawiam

edytowany 2x, ostatnio: kq
bl4ster
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Lublin
  • Postów:197
0

ponieważ w ostatnim kroku pętli porównujesz z ostatnim elementem, który jest znakiem końca tablicy.

Kopiuj
if(tekst[i]==tekst[i+1]){

Tutaj, jeśli tekst[5], to tu w ostatnim kroku, porównujesz tekst[4]z tekst[5].


"Jesteśmy świadomymi istotami, a życie jest sposobem w jaki wszechświat poznaje sam siebie." prof. Brian Cox
edytowany 1x, ostatnio: bl4ster
szweszwe
Znakiem końca tablicy?
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:3 dni
  • Lokalizacja:Szczecin
2

Dlatego, że długość stringa się zmienia po usunięciu z niego znaków.


MI
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 8 lat
  • Postów:11
0
kq napisał(a):

Dlatego, że długość stringa się zmienia po usunięciu z niego znaków.

Oczywiście! Dziękuje za trafna uwagę. Pozdrawiam

carlosmay
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Pabianice
1

https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Korzystaj z metod udostępnionych przez klasę std::string,
prawie identycznie jak dla kontenera w linku.


kq
Chciałem nawet się zaautopromować, ale tutaj masz odniesienie do następnego elementu tablicy. Owszem, jest to jak najbardziej do zrobienia z erase-remove ale nie jestem pewien czy to by było takie piękne.
MI
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 8 lat
  • Postów:11
0
midodej napisał(a):

Witam serdecznie,
Dlaczego po skompilowaniu wyrzuca mi komunikat:
terminate called after throwing an instance of std::out of range.

kod funkcji:

Kopiuj
size_t dlugosc = tekst.size();
    for(int i=0;i<dlugosc-1;i++){
        if(tekst[i]==tekst[i+1]){
            tekst.erase(i,1);
        }
    }

pozdrawiam

to nie przez to, zabezpieczyłem się przed tym warunkiem w pętli dlugosc-1..
Odpowiedź padła ze strony moderatora przecież długość zmiennej się zmienia. Temat do zamknięcia.

pozdrawiam

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:3 dni
  • Lokalizacja:Szczecin
1

Rozwijając ciut wypowiedź @carlosmay (+mój komentarz), wzorując się na

Kopiuj
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);
}

Możesz napisać coś takiego:

Kopiuj
auto e = remove_if(s.begin(), prev(s.end()), [](char const& c){
    return c == (&c)[1];
});
s.erase(e, s.end());

link

Wydaje mi się, że to w pełni zdefiniowane zachowanie (zakładając co najmniej 1-elementowy s), ale i tak trochę zalatuje hackiem ((&c)[1])


Azarien
hakiem to zalatuje prev(s.end()) jeżeli jest s.back() ;-)
kq
back() zwraca referencję do elementu, remove_if oczekuje iteratorów.
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

Bez "hacków":

Kopiuj
char prev_c = 0;
auto it = std::remove_if(s.begin(), 
					s.end(), 
					[&prev_c](char c) 
					{ 
						bool res = prev_c == c; 
						prev_c = c; 
						return res; 
					});
s.erase(it, s.end());

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.