Iterator invalidation rules for std::deque
When do std::deque
operations invalidate iterators?
An iterator is considered invalidated if it no longer points to the same element it originally pointed to.
For std::deque
, the iterator invalidation rules are as follows:
- End iterators: The end iterator (the one returned by
end()
) is always invalidated when the deque is modified. - Insertion: Insertion in the middle of the deque invalidates all iterators. Insertion at either end (using
push_front()
,emplace_front()
,push_back()
,emplace_back()
) only invalidates the end iterator. - Erasure: Erasing an element in the middle of the deque invalidates all iterators. Erasing an element at either end (using
pop_front()
orpop_back()
) only invalidates the end iterator and the iterators to the erased elements. - Clear: Calling
clear()
invalidates all iterators. - Swap: Calling
swap()
invalidates all iterators.
Here's an example demonstrating iterator invalidation:
#include <deque>
#include <iostream>
int main() {
std::deque<int> d{1, 2, 3, 4, 5};
auto it = d.begin();
auto end = d.end();
d.push_front(0);
// This is fine, it still points to the element 1
std::cout << *it << "\n";
// This is invalid, end iterator is invalidated
std::cout << *(end - 1) << "\n";
d.insert(it + 2, 10);
// This is invalid, it no longer points to 1
std::cout << *it << "\n";
}
The previous example results in undefined behaviour. With debug flags enabled, the compiler may detect the problem and throw a run time error:
cannot deference out of range deque iterator
To avoid issues with iterator invalidation, it's often best to reacquire iterators after any operation that could potentially invalidate them.
Double-Ended Queues using std::deque
A guide to double-ended queues - a structure that behaves like a vector, specialised for manipulating objects at the edges of the collection