1. What is iterator failure?
In C++, an iterator is a pointer-like object used to traverse STL containers (such as vector, list, map, etc.).
Iterator failedIt means that after performing certain operations on the container (such as insertion and deletion), the originally valid iterator becomes unavailable. Continuing to use it will cause undefined behavior (Undefined Behavior, UB), such as program crashes, data errors, etc.
2. What operations will cause the iterator to fail?
Different containers have different iterator failure rules, this article mainly discussesvector
Iterator failure problem.
2.1 vector insert operation (push_back, insert)
Whenvector
When inserting an element:
-
if
size() == capacity()
(Capacity full):-
vector
The larger memory will be re-allocated and the original data will be copied. -
All iterators fail(include
begin()
,end()
wait).
-
-
if
size() < capacity()
(Capacity not full):- The iterator before the insertion point is still valid。
- The insertion point and subsequent iterator fail(because elements may be moved).
Example: push_back causes the iterator to fail
vector<int> v = {1, 2, 3}; auto it = (); // it points to 1v.push_back(4); // Reallocation of memory may be triggeredcout << *it; // ❌ Danger!it Possible failure
How to avoid it?
-
Reserve space in advance(
reserve()
):
vector<int> v; (100); // Reserve 100 elements of spaceauto it = (); v.push_back(1); // Will not be reassigned,it Still valid
- Use index instead of iterator(if allowed).
2.2 vector deletion operation (erase, pop_back)
Whenvector
When deleting elements:
- The iterator of the deleted element is invalid。
- All iterators after the deleted element are invalid(because the subsequent elements will move forward).
- The iterator before deleting the point is still valid。
Example: erase causes the iterator to fail
vector<int> v = {1, 2, 3, 4}; auto it = () + 2; // it points to 3(() + 1); // Delete 2cout << *it; // ❌ Danger!it Have expired(3 Already moved forward)
How to delete correctly?
-
use
erase
The return value of(Return to the next valid iterator):
vector<int> v = {1, 2, 3, 4}; auto it = (); while (it != ()) { if (*it % 2 == 0) { it = (it); // Delete and update it } else { it++; // Otherwise, it will increase normally } }
Reverse traversal(Avoid iterator failure)
for (auto it = (); it != (); ) { if (*it % 2 == 0) { it = vector<int>::reverse_iterator((() - 1)); } else { it++; } }
3. Iterator failure of other containers
container | Insert operation (insert) | Delete operation (erase) |
---|---|---|
vector |
Possible failure (depending on capacity) | Delete and subsequent invalidation |
deque |
Possible failure (start and end) | Deleted and nearby invalid |
list |
Will not fail | Only deleted invalid |
map /set
|
Will not fail | Only deleted invalid |
4. Summary
-
vector
When inserting:- Possible failure(If reassignment is triggered).
-
How to avoid it:in advance
reserve()
Or use index.
-
vector
When deletion:- Deleted and subsequent iterators fail。
-
The correct way to do it:use
erase
Return value or reverse traversal.
-
Other containers(like
list
、map
) is usually safer, but still requires caution.
Best Practices:
- Avoid directly modifying containers during traversal, unless it is explicitly known whether the iterator is valid.
-
Try to use
range-based for
Or algorithm (such asremove_if
), reduce manual management of iterators. -
Used during debugging
-D_GLIBCXX_DEBUG
(GCC) Detect iterator errors.
The above is the detailed content of the guide to avoid pit failure of C++ iterator. For more information about C++ iterator failure, please pay attention to my other related articles!