If I have an iterator into vector a
, then I move-construct or move-assign vector b
from a
, does that iterator still point to the same element (now in vector b
)? Here's what I mean in code:
#include <vector> #include <iostream> int main(int argc, char *argv[]) { std::vector<int>::iterator a_iter; std::vector<int> b; { std::vector<int> a{1, 2, 3, 4, 5}; a_iter = a.begin() + 2; b = std::move(a); } std::cout << *a_iter << std::endl; // Is a_iter valid here? return 0; }
Is a_iter
still valid since a
has been moved into b
, or is the iterator invalidated by the move? For reference, std::vector::swap
does not invalidate iterators.
Iterator Invalidation Example on Element Insertion in vector: When a new element is inserted in vector then it internally shifts its elements and hence the old iterators become invalidated.
Iterator Invalidation in C++ When the container to which an Iterator points changes shape internally, i.e. when elements are moved from one position to another, and the initial iterator still points to the old invalid location, then it is called Iterator invalidation. One should be careful while using iterators in C++.
To avoid invalidation of references to elements you can use a std::deque if you do not insert or erase in the middle. To avoid invalidation of iterators you can use a std::list.
std::move. std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
While it might be reasonable to assume that iterator
s are still valid after a move
, I don't think the Standard actually guarantees this. Therefore, the iterators are in an undefined state after the move
.
There is no reference I can find in the Standard which specifically states that iterators that existed before a move
are still valid after the move
.
On the surface, it would seem to be perfectly reasonable to assume that an iterator
is typically implemented as pointers in to the controlled sequence. If that's the case, then the iterators would still be valid after the move
.
But the implementation of an iterator
is implementation-defined. Meaning, so long as the iterator
on a particular platform meets the requirements set forth by the Standard, it can be implemented in any way whatsoever. It could, in theory, be implemented as a combination of a pointer back to the vector
class along with an index. If that's the case, then the iterators would become invalid after the move
.
Whether or not an iterator
is actually implemented this way is irrelevant. It could be implemented this way, so without a specific guarantee from the Standard that post-move
iterators are still valid, you cannot assume that they are. Bear in mind also that there is such a guarantee for iterators after a swap
. This was specifically clarified from the previous Standard. Perhaps it was simply an oversight of the Std comittee to not make a similar clarification for iterators after a move
, but in any case there is no such guarantee.
Therefore, the long and the short of it is you can't assume your iterators are still good after a move
.
23.2.1/11 in Draft n3242 states that:
Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.
This might lead one to conclude that the iterators are valid after a move
, but I disagree. In your example code, a_iter
was an iterator in to the vector
a
. After the move
, that container, a
has certainly been changed. My conclusion is the above clause does not apply in this case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With