Reputation: 1076
The most popular post on C++ Iterator invalidation rules claims that it's not clear if the past-the-end iterators (i.e., those returned by end()
, cend()
, rend()
, and crend()
) are invalidated according to the same rules as normal iterators, which point to elements in the container. These claims, made for both 2003 and 2011 C++, defer to a post discussing End iterator invalidation rules, where the accepted answer suggests that the 2003 standard is ambiguous on the matter. This conclusion is based on a comment in 23.1/10 (in the context of swap()
) that seems to imply that when the spec does not explicitly mention invalidation of past-the-end iterators, they may be invalidated.
A comment on that post's question (by mike-seymour) suggests that C++11 is unambiguous on this matter, in the case of deque
s. My question is about all containers:
Said differently,
Upvotes: 26
Views: 3873
Reputation: 224049
My question is about all containers:
- In C++11, are there any container operations that may invalidate a past-the-end iterator, and where this behavior is ambiguous in the language specification?
I am not sure what you mean with "where this behavior is ambiguous in the language specification", but there certainly are operations that invalidate past-the-end iterators (like insert into a std::vector
or std::string
).
Said differently,
- Can I trust the validity of a past-the-end iterator after performing a container operation that does not say it may invalidate the past-the-end iterators?
You can trust the past-the-end iterator like any other iterator: Any operation that does not (potentially) invalidate iterators won't invalidate them. Except for the possibility of the standard sporting a bug, that is all operations where it doesn't say that they (potentially) invalidate operators.
Upvotes: 13
Reputation: 1568
Regarding end iterator's invalidation rules, there is a mention in cppreference.com#Iterator_invalidation.
The relevant lines are:
The past-the-end iterator deserves particular mention. In general this iterator is invalidated as though it were a normal iterator to a non-erased element. So std::set::end is never invalidated, std::unordered_set::end is invalidated only on rehash, std::vector::end is always invalidated (since it is always after the modified elements), and so on.
There is one exception: an erasure which deletes the last element of a std::deque does invalidate the past-the-end iterator, even though it is not an erased element of the container (or an element at all). Combined with the general rules for std::deque iterators, the net result is that the only modifying operation which does not invalidate std::deque::end is an erasure which deletes the first element, but not the last.
Also see a test with std::set's end() - https://godbolt.org/z/5ecdqYod3.
Upvotes: 1
Reputation: 416
At least in GCC end iterator gets invalidated for 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
}
Upvotes: 0
Reputation: 7766
You should be able to trust it if the standard says the operation will not invalidate iterators. Anything else should be treated as a bug in the standard library implementation.
Upvotes: 2