Я отвечаю здесь, поскольку другие ответы устарели; тем не менее, они были не совсем правы в этом вопросе.
Во-первых, C ++ 14 изменил правила, упомянутые в вопросе. Направление через недопустимое значение указателя или передача недопустимого значения указателя в функцию освобождения все еще не определено, но другие операции теперь определяются реализацией, см. Документация по преобразованию "недопустимого значения указателя" в реализациях C ++ .
Во-вторых, слова имеют значение. Вы не можете обойти определения при применении правил. Ключевым моментом здесь является определение «недействительным». Для итераторов это определяется в [iterator.requirements] . На самом деле, даже верно, что указатели являются итераторами , значения «недопустимых» для них немного отличаются. Правила для указателей отображают «недопустимый» как «не косвенный через недопустимое значение», что является частным случаем «не разыменовываемый » для итераторов; однако «не допускается» - это , а не , что означает «недопустимый» для итераторов. «Недопустимый» явно определен как « может быть единственным », тогда как «единственное» значение определено как «не связанный с какой-либо последовательностью» (в том же абзаце определения «разыменованный»). В этом абзаце даже явно определены «ценности прошлого».
Из текста стандарта в [iterator.requirements] ясно, что:
- Прошлые значения не считаются разыменованными (по крайней мере, стандартной библиотекой), как заявляет стандарт.
- Обращающиеся значения не являются единичными, поскольку они связаны с последовательностью.
- Прошлые значения не являются единичными, поскольку они связаны с последовательностью.
- Итератор не является недействительным, если он определенно не является единичным (отрицанием определения «недопустимый итератор»). Другими словами, , если итератор связан с последовательностью, он не является недействительным.
Значение end()
является последним значением, которое связано с последовательностью до ее аннулирования. Так что это действительно допустимо по определению. Даже при неверном понимании буквально «неверно» правила указателей здесь не применимы.
Правила, разрешающие ==
сравнение с такими значениями, содержатся в требованиях к входным итераторам , которые наследуются некоторой другой категорией итераторов (прямой, двунаправленный и т. Д.). Более конкретно, действительные итераторы должны быть сопоставимы в домене итератора таким образом (==
). Кроме того, в требованиях прямого итератора указано, домен находится над базовой последовательностью . А требования к контейнерам определяют типы элементов iterator
и const_iterator
в любой категории итераторов, удовлетворяющие требованиям прямого итератора . Таким образом, ==
для end()
и итератор для одного и того же контейнера должны быть четко определены. Как стандартный контейнер, vector<int>
также подчиняется требованиям. Вот и вся история.
В-третьих, даже когда end()
является значением указателя (это может произойти при оптимизированной реализации итератора vector
экземпляра), правила в вопросе все еще не применимы. Причина упомянута выше (и в некоторых других ответах): «неверный» относится к *
(косвенный сквозной), а не к сравнению. Стандартно разрешено сравнивать одно конечное значение определенным образом. Также обратите внимание, что ISO C ++ не является ISO C, они также слегка не совпадают (например, для <
для значений указателей, не входящих в один и тот же массив (не указано и не определено), хотя здесь действуют аналогичные правила.