2010-08-20 3 views
1
void trim(string &str) 
{ 
    string::iterator it = str.begin(); 
    string::iterator end = str.end() - 1; 

    // trim at the starting 
    for(; it != str.end() && isspace(*it); it++) 
     ; 
    str.replace(str.begin(), it, ""); 

    // trim at the end 
    for(; end >= str.begin() && isspace(*end); end--) 
     ; 
    str.replace(str.end(), end, ""); // i get the out_of_range exception here 
} 

Я хочу обрезать строку пробелов. Сначала я запускаю пробелы от начала, и он отлично работает, а затем я нахожу положения пробелов с конца и пытаюсь удалить его, и это вызывает исключение.Почему моя функция обрезки не работает?

Почему?

ответ

7

Изменение строки аннулирует итераторы в строку. Один из способов исправить это - изменить строку только один раз. Кстати, это также может быть быстрее:

void trim(std::string &str) 
{ 
    std::string::size_type begin=0; 
    while(begin<str.size() && isspace(str[begin])) 
     ++begin; 
    std::string::size_type end=str.size()-1; 
    while(end>begin && isspace(str[end])) 
     --end; 
    str = str.substr(begin, end - begin + 1) 
} 
+0

Разве вы не сделали переменные слишком местными? – UncleBens

+0

@UncleBens: Да, черт возьми. Исправлено. – sbi

2

Итераторы действительны только до тех пор, пока вы не измените строку. Как только вы меняете строку, конечный итератор наверняка становится недействительным.

Вам необходимо восстановить итераторы после каждого действия, которое могло бы изменить строку.

+2

У него есть свой собственный конец: string :: iterator end = str.end() - 1; – celavek

+0

Я имею в виду, что он не пытается разыменовать итератор строки end() в isspace (* end), он пытается попробовать свой собственный сохраненный конец (что может быть недействительным). – celavek

+0

@ Мариус: Верно, исправлено. – sharptooth

-1

str.end() не относится ни к какой позиции со строкой; следовательно, если вы попытаетесь разыменовать его, вы получите исключение.

+0

Xolve не разыскивает конечный итератор. (Также, как правило, это не привело бы к исключению исключения.) – sbi

3

Я предложил бы просто использовать boost::trim

+0

Я не вижу, как это хороший ответ на вопрос. Может быть, хороший комментарий. -1 от меня. – UncleBens

+0

@UncleBens, потому что он явно заявляет: «Я хочу урезать пробелы», а не «Я изучаю путь вокруг строк, это какой-то код, который я написал, что с ним не так»? или что-то подобное – Pieter

0

Проблема заключается в том, что вы храните итератор для последнего символа в строке, и использовать его только после того, как вы (потенциально) удалены символы из строки, так что хранимая итератор теперь недействителен (больше не указывая на последний символ).

Это поможет объявить переменные как можно ближе к их первому использованию. В частности, итераторы, как правило, становятся недействительными настолько легко, что вы, как правило, избегаете удерживать их дольше, чем это необходимо.

Итак, инициализируйте конечный итератор после того, как вы удалили ведущие пробелы. (Можно было бы также рассмотреть вопрос о снятии завершающих пробелов первыми.)


Могу ли я также предлагаю использовать функцию erase члена для удаления символов из строки.

Могут возникнуть другие ошибки в стирании пробелов, но вы можете понять, когда вы туда попадете.

Смежные вопросы