Я пытаюсь выполнить обратную итерацию по строке, но получаю ошибку утверждения для оператора [] в последней версии VS.
int foo() {
std::string s = "s";
for (int i = (s.size() - 1); i >= 0; i--) {
std::cout << s[i] << std::endl;
}
return 0;
}
Комментирование строки cout дает предупреждение о бесконечном цикле и действительно входит в бесконечный цикл:
int foo2() {
std::string s = "s";
for (int i = (s.size() - 1); i >= 0; i--) {
//std::cout << s[i] << std::endl;
}
return 0;
}
Итерации вперед прекрасно работают как с циклом for, так и без него:
int bar() {
std::string s = "s";
for (int i = 0; i < s.size(); i++) {
std::cout << s[i] << std::endl;
}
return 0;
}
Я использую стандарт С++ 14 и тот же код, который использовался для работы с другими компиляторами/старыми версиями VS. Та же проблема существует для любого размера строки (хотя это не имеет значения). Я понимаю, что могу изменить код для использования и разыменования указателя вместо использования int, но хочу понять, почему это больше не работает, почему это небезопасно или неправильно, или что еще мне не хватает. Спасибо!
@PaulMcKenzie Где вы нашли здесь неопределенное поведение?!
@VladfromMoscow -- Просто читаю заявление комментаторов -- Я использую стандарт С++ 14, и тот же код используется для работы с другими компиляторами/старыми версиями VS.
Вы уверены, что именно в этом ваша проблема? На самом деле в вашем коде нет никаких проблем, кроме преобразования std::size_t
в int
, и ваши примеры кода правильно работают в gcc/clang/msvc для меня.
Commenting out the cout line gives infinite loop warning and indeed enters infinite loop
s.size()
— это unsigned long
, поэтому оно никогда не может быть меньше 0
. Поведение сужающего преобразования из-за присвоения unsigned long
к int
является поведением, определяемым реализацией, хотя это не должно быть проблемой при присвоении unsigned long
значения 0 к int
, по крайней мере, я так не думаю, но кто знает, у MSVC есть свои причуды.
Похоже, компилятор достаточно умен, чтобы предсказать, что не может быть бесконечного цикла, когда присутствует это конкретное тело цикла for
, что наводит меня на мысль, что при доступе к массиву может быть выдано исключение, возможно, за пределами доступа.
Использование отладчика для отслеживания значения i
— лучший способ понять, что происходит.
Где там в цикле использовалось отрицательное значение i?!
Дело в том, что я вообще не должен превышать 0 по критерию цикла "i >= 0;"
@Z_C, сделай одолжение, в коде после строки std::string s = "s";
добавь строку std::cout << s.size() - 2;
и посмотри, что получится.
@anastaciu входит в бесконечный цикл, но на этот раз печатает экран, полный чисел. Также, если я что-то не упустил, он не должен выходить за пределы нуля не потому, что s.size() не может быть отрицательным, а потому, что буквально это было критерием цикла for .
нет, 18446744073709551615
О, хорошо, это максимальное значение 8-байтового беззнакового длинного - 1, принцип тот же, теперь вы видите, что i
никогда не будет отрицательным, не так ли?
Z_C извините, я думал, что вы используете auto i
, поэтому, если i
это int
, мой ответ не применим.
теперь я попробовал с auto, затем с int, и auto дает бесконечный цикл и / или ошибку утверждения, а с int он отлично себя ведет. не знаю, что происходит... число все еще 18446744073709551615, хотя
@Z_C, что и следовало ожидать, вы все равно печатаете значение, назначение int сужается от unsigned long, его реализация определяет, как это должно работать, но присвоение unsigned long
значения 0
int
не должно быть проблемой, поэтому неясно почему ваш код делает то, что он делает.
@Z_C используйте отладчик, чтобы отследить значение i
и посмотреть, к чему оно вас приведет.
@Z_C, то есть поместите точку останова в строку цикла for, запустите его и используйте F10, чтобы перейти, вы можете отслеживать значение i в разделителе Locals ниже.
@VladfromMoscow Я неправильно прочитал, и у меня сложилось впечатление, что ОП использует auto i
, так что вы правы, мой диагноз был неверным.
@anastaciu Я думаю, что вы были правы с самого начала, я думаю, что оригинал мог быть ошибкой обновления, когда я изменил типы переменных, и именно auto выдает ошибки, с int все в порядке. С int i инициализируется правильно, затем уменьшается до 0, после чего цикл останавливается. С auto он уменьшается до нуля, затем меняется на 18446744073709551615 и так далее. Так что, похоже, действительно автоматически назначается unsigned int. Единственный вопрос: почему цикл не останавливается, когда i становится 0?
@Z_C а, я так и знал :D В любом случае, кроме шуток, я рад, что ты решил свою проблему.
Может ли быть так, что ваш int по умолчанию является беззнаковым и, следовательно, уменьшается, когда i = 0 приводит к высокому значению?
Как упоминал @PeteBecker, int должен быть подписан и не должен переполняться. Однако я предполагаю, что ваш фактический код не использует int.
я не должен уменьшаться после 0
№ int
всегда подписан. Просто char
может быть как подписанным, так и не подписанным.
@PeteBecker: согласен, но я предполагаю, что его минимальный пример - это не тот, который зацикливается бесконечно, и что в его реальном коде он использует size_t i.
@gchapuis - вы можете отредактировать свой ответ, чтобы сказать это.
@PeteBecker Вот, пожалуйста :)
На самом деле проблема изначально была вызвана «auto» i, а не «int» i, но не обновлена должным образом. Auto дал i тип unsigned int, который переполнил оператор [] или вызвал переключение бесконечного цикла с нуля на 18446744073709551615 после завершения цикла i = 0 и выполнения i--.
Спасибо всем за полезные ответы!
Я не понимаю, как этот цикл for (int i = (s.size() - 1); i >= 0; i--) { может быть бесконечным циклом for, когда s.size() не равен 0 .