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 iteratorTo 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