Недействительность прошедшего итератора на С++ 11
Самый популярный пост в С++ Правила аннулирования Iterator утверждают, что он не ясен, если итераторы прошедшего конца (т.е. те, которые возвращаются end()
, cend()
, rend()
и crend()
) недействительны в соответствии с теми же правилами, что и обычные итераторы, которые указывают на элементы в контейнере. Эти претензии, сделанные как для С++, так и для С++, откладывают до публикации обсуждения правил аннулирования конца итератора, где принятый ответ предполагает, что стандарт 2003 года неоднозначен по этому вопросу. Этот вывод основан на комментарии в 23.1/10 (в контексте swap()
), который, по-видимому, подразумевает, что, когда спецификация явно не упоминает о недействительности итераторов прошлого, они могут быть признаны недействительными.
Комментарий к этому вопросу (майк-сеймур) предполагает, что С++ 11 однозначен в этом вопросе, в случае deque
s. Мой вопрос касается всех контейнеров:
- В С++ 11 существуют ли какие-либо операции с контейнерами, которые могут привести к аннулированию итератора прошедшего конца, и где это поведение неоднозначно в спецификации языка?
Говорят иначе,
- Могу ли я доверять действительности прошедшего конца итератора после выполнения операции с контейнером, которая не говорит о том, что это может привести к аннулированию итераторов прошедшего конца?
Ответы
Ответ 1
Мой вопрос касается всех контейнеров:
- В С++ 11 существуют ли какие-либо операции с контейнерами, которые могут привести к аннулированию итератора прошедшего конца, и где это поведение неоднозначно в языковая спецификация?
Я не уверен, что вы имеете в виду под "там, где это поведение неоднозначно в спецификации языка", но, безусловно, есть операции, которые делают недействительными прошлые операторы (например, вставлять в std::vector
или std::string
).
Говорят иначе,
- Могу ли я доверять действительности прошедшего конца итератора после выполнения операции с контейнером, которая не говорит о том, что она может аннулировать итераторы прошедшего конца?
Вы можете доверять итератору прошедшего конца, как и любой другой итератор: любая операция, которая не делает (потенциально) недействительными итераторы, не приведет к их аннулированию. За исключением возможности стандартной спортивной ошибки, то есть все операции, в которых она не говорит, что они (потенциально) недействительны для операторов.
Ответ 2
Вы должны быть в состоянии доверять ему, если в стандарте указано, что операция не приведет к аннулированию итераторов. Все остальное должно рассматриваться как ошибка в стандартной реализации библиотеки.
Ответ 3
По крайней мере, в конце GCC итератор становится недействительным для std:: map:
#include <set>
#include <stdlib.h>
#include <assert.h>
int main() {
std::set<int> a;
a.insert(1);
std::set<int>::reverse_iterator rit(a.rbegin());
++rit;
assert(rit==a.rend());
a.erase(a.begin());
assert(a.rend()==rit); // FAIL
}