In practice, a vector is a code-maintained contiguous buffer of data. Each element is set up adjacent to the next in an array-like fashion.
When elements move around, in practice, they just move around. Pointers point to locations in that buffer, so if the element moves, in practice the pointer just ends up pointing somewhere else.
However, the C++ standard is more strict. When an iterator is invalidated, so are references and pointers to that location. There are a number of operations that can invalidate an iterator that do not, logically, change the fact that the array is actually going to be the same buffer. For example, if you .erase
an element, it invalidates every iterator at that location and afterwards.
In practice a pointer to the element will end up pointing at what was the "next" element in the list, but the standard doesn't guarantee that.
std::shuffle
does not invalidate any iterators. It just changes the values stored there. So a pointer to the nth element will both in practice, and in theory, still point to the nth element.
When the vector is expanded, if you expand it beyond .capacity()
, all iterators are invalidated. In practice it actually moves the data to a new location, and the pointers are now danging pointers.
When you reduce (via .erase(it)
or .erase(a,b)
), all iterators at or after the first argument are invalidated. This means that references and pointers to these elements are also invalidated. In practice, they will now refer to elements "further down the chain" (if such elements exist), as neither .erase
will cause your buffer to reallocate, but this is not guaranteed by the standard.
There are other operations that can invalidate iterators. .shrink_to_fit()
can, as can vector<X>(vec).swap(vec)
(the C++03 version of shrink-to-fit), and .reserve()
and operations that grow the size beyond .capacity()
.
The operations that cause .capcity()
to change will actually make your pointers invalid (or those that make the pointers point beyond-the-end) in practice and in theory.