It is not allowed to de-reference the end()
iterator. Doing so causes undefined behavior. It doesn't refer to any element of the container, but one past the last element.
The reason that end()
"points" after the last element, is that it is necessary to distinguish empty containers. If end()
was referring to the last element and begin()
to the first, then if begin() == end()
that would mean that there is one element in the container and we can't distinguish the case of an empty container.
For containers that support it, to access the last element of the container you can use .back()
, which will return a reference, not an iterator. But this is only allowed if there is a last element, i.e. if the container is not empty. Otherwise you have again undefined behavior. So check .empty()
first if necessary.
std::set
does not have the back()
member and is not really intended to be used this way, but if you really want to access the last element, which is not the last element in the constructor initializer list, but the last element in the <
order of the elements, then you can use std::prev(el.end())
or el.rbegin()
("reverse begin") which will give you an iterator to the last element. Again, dereferencing this iterator is only allowed if the container is not empty. (For std::prev
forming the iterator itself isn't even allowed if the container is empty.)
Undefined behavior means that you will have no guarantees on the program behavior. It could output something in one run and something else in another. It could also output nothing, etc.
There is no requirement that you will get the output you see. For example, current x86_64 Clang with libc++ as standard library implementation, compiles (with or without optimization) a program that prints 0
twice. https://godbolt.org/z/nWMss1fqe
Practically speaking, assuming the compiler didn't take advantage of the undefined behavior for an optimization that drastically changes the program from the "intended" program flow, you will likely, depending on the implementation of the standard library, read some internal memory of the std::set
implementation in the standard library, get a segmentation fault if the indirection points to inaccessible memory or incidentally (with no guarantees) refer to other values in the container.