Consider the following program:
struct list_wrapper
{
std::vector<int> m_list;
};
int main()
{
std::vector<int> myList { 1, 1, 2, 3, 5 };
const std::vector<int>::iterator iter = myList.begin();
list_wrapper wrappedList;
wrappedList.m_list = std::move(myList);
// Can I still dereference iter?
return 0;
}
After the call to std::move(myList)
, does iter
now point to a valid item inside wrappedList.m_list
, or do move constructors/assignments invalidate all iterators?
For reference, std::vector::swap does not invalidate iterators.
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.
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.
The move iterator wraps another iterator, and returns an r-value reference of what the wrapped iterator returns when it is dereferenced. When dereferenced (with * or ->), STL containers (like vectors) iterators return a reference to the element they point to.
The purpose of the move iterator is to allow the STL to move the objects it manipulates, instead of copying them. Indeed, the STL makes copies by default. In the following example: std::vector<std::string> source = { "Move", "iterators", "in", "C++" }; std::vector<std::string> destination (begin (source), end (source));
There is a way to lose your data when using move iterators. The idea is that if the elements in source are moved to some other place than destination, then in the end they are neither in source nor in destination so they are effectively lost.
When dereferenced (with * or -> ), STL containers (like vectors) iterators return a reference to the element they point to. Dereferencing a move iterator has the equivalent effect of calling std::move on the reference returned by the wrapped iterator, to convert it into an r-value reference.
After http://en.cppreference.com notes (emphasis mine):
After container move assignment (overload (2)), unless elementwise move assignment is forced by incompatible allocators, references, pointers, and iterators (other than the end iterator) to other remain valid, but refer to elements that are now in *this. The current standard makes this guarantee via the blanket statement in §23.2.1[container.requirements.general]/12, and a more direct guarantee is under consideration via LWG 2321
Notes
As hvd have rightly pointed out there is at least once case where the move assignent is forced to invalidate iterators - when the new container has incompatible allocator.
As Ben Voigt noted there is a broader discussion in this topic over here and it actually already covers the c++11 aspects of the question...
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