Почему в строке C ++ после последнего символа поведение отличается при доступе по index и at ()? - PullRequest
0 голосов
/ 02 июля 2019
string ss("test");
cout << ss[ss.size()] ;

Выходное значение равно нулю, программа нормально завершается, но при запуске этой программы с помощью at ()

string ss("test");
cout << ss.at(ss.size()) ;

выдает исключение.У меня вопрос: не должны ли оба поведения быть одинаковыми или оба (доступ по индексу и at ()) приводят к ненормальному завершению или выходу нормально?

Ответы [ 2 ]

2 голосов
/ 02 июля 2019

не должны ли оба поведения быть одинаковыми или оба (доступ по индексу и at ()) дают ненормальное завершение или нормально завершаются?

Нет, они не должны иметь одинаковое поведение,Поведение преднамеренно отличается.Если бы это было не так, то существовал бы только один из них.

Функция-член at выполняет проверку границ.Любой доступ за пределы контейнера приводит к исключению.Это то же самое, что и функция-член at, например, std::array или std::vector.Обратите внимание, что необработанный бросок приведет к завершению программы.

Оператор индекса не выполняет никаких проверок за пределами.До C ++ 11 любой доступ к элементам с индексами > size() имел неопределенное поведение.Ни при каких обстоятельствах оператор индекса не может выдать исключение.Это аналогично оператору индекса массива, например std::array или std::vector.

Начиная с C ++ 11, поведение оператора индекса std::string было изменено так, что чтение элементапо индексу == size() (т. е. один после последнего элемента) четко определен и возвращает нулевой терминатор.Только изменение объекта через возвращенную ссылку имеет неопределенное поведение.Чтение других индексов за пределами границ по-прежнему ведет к неопределенному поведению.

Я не знаю, на самом деле, чтобы не вносить соответствующее изменение в at, чтобы разрешить доступ к нулевому терминатору, но я подозреваю, что это считалосьбыть назад несовместимым изменением.Правильное определение UB всегда обратно совместимо, а прекращение исключения - нет.Другая возможная причина состоит в том, что он открыл бы маршрут к UB (если нулевой терминатор был изменен), и конструкция at заключается в том, чтобы освободить его от UB.

0 голосов
/ 02 июля 2019
  1. operator[] не проверяет, является ли индекс действительным, и вызывает неопределенное поведение, когда индекс выходит за пределы диапазона. Важно, что последний символ действителен ('\ 0') при использовании operator[], ss[ss.size()] = ss[4] = '\0'. Таким образом, вывод равен нулю, программа завершается нормально. Пожалуйста, попробуйте cout << ss[ss.size() + 1], вы получите ошибку.
  2. ss.at(ss.size()): последний символ ('\ 0') InvalidPassing неверный индекс (меньше 0 или больше или равно size ()) создает исключение out_of_range:: https://www.geeksforgeeks.org/string-at-in-cpp/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...