Могу ли я разыменовать std :: string.end ()? - PullRequest
7 голосов
/ 08 мая 2020

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

Стандарт C ++ 11 заявляет, что вы можете прочитать один индекс после конец строки. string[size()] ссылается на доступное только для чтения значение нулевого терминатора.

24.3.2.5 доступ к элементу basic_string [string.access]

const_reference operator[](size_type pos) const;

reference operator[](size_type pos);

(1) Требуется: pos <= size().

(2) Возвращает: *(begin() + pos) if pos < size(). В противном случае возвращает ссылку на объект типа charT со значением charT(), где изменение объекта на любое значение, отличное от charT(), приводит к неопределенному поведению.

front() определяется чтобы быть эквивалентным return operator[](0), что эквивалентно return operator[](size()) для пустой строки.

end() - begin() четко определено как разница длины строки, поэтому end() должно указывать с индексом size() для разумной реализации, чтобы определить эту арифметику c.

В приведенном выше стандартном отрывке operator[](pos) эквивалентно *(begin() + pos) if pos < size(). не говорит, что вы можете разыменовать begin() + size(), но считаете ли вы разумным предположить, что это должно быть четко определено? Или еще лучше, знаете ли вы какое-либо доказательство, освобождающее строковые итераторы от ограничения?

Кроме того, можно ли доказать, что *(begin() + i) для любого i эквивалентно operator[](i)?

Ответы [ 2 ]

4 голосов
/ 08 мая 2020

Из определения string.end () :

Возвращает: Итератор, который представляет собой значение после конца.

и из определения после конца :

... Такое значение называется значением после конца. Значения итератора i, для которого определено выражение * i, называются разыменуемыми. Библиотека никогда не предполагает , что значения за пределами конца могут быть разыменованы. ...

Акцент мой, и я предполагаю, что любое исключение, сделанное для std::string, будет упомянуто в первой ссылке. Поскольку это не так, разыменование std::string.end() не определяется по пропуску.

3 голосов
/ 08 мая 2020

Может показаться, что в случае std::string это должно быть возможно, поскольку само собой разумеется, что это нулевой терминатор, но это все еще неопределенное поведение:

https://en.cppreference.com/w/cpp/string/basic_string/end

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

© ISO / IECN4659 § 27.2.1 - 7

... для любого итератора type есть значение итератора, которое указывает за последний элемент соответствующей последовательности. Эти значения называются значениями после конца ... Библиотека никогда не предполагает, что значения после конца можно разыменовать ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...