迭代器失效(迭代器及时跟新或者使用索引(类似数组))

迭代器失效(Iterator Invalidation)

在 C++ 中,迭代器失效(Iterator Invalidation)指的是 迭代器在容器发生修改后变得无效,访问它会导致未定义行为(UB)。迭代器失效通常发生在 删除(erase)、插入(insert)、扩容(resize)、清空(clear) 等操作后。


1. 迭代器失效的常见情况

(1)删除元素(erase() 导致迭代器失效)

  • vectordequelist 等容器中,删除元素可能会使当前迭代器后续迭代器失效。
✅ 解决方法
  • 对于 vectordeque,删除元素后,必须更新迭代器
  • 对于 listunordered_maperase() 仅使当前迭代器失效,后续迭代器仍然有效。

示例:vector 的 erase()

#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto it = v.begin() + 2;  // 指向 v[2] (3)
    
    v.erase(it);  // 删除 v[2] (3),导致迭代器失效

    std::cout << *it;  // ❌ 未定义行为(UB),it 失效
}
✅ 解决方法
auto it = v.erase(it);  // `erase()` 返回删除元素的下一个迭代器
std::cout << *it;  // ✅ 安全

(2)插入元素(insert() 可能导致扩容)

  • 对于 vectordeque,如果 insert() 触发 扩容(reallocation),则所有迭代器都会失效。
  • listmapinsert() 不会使已有迭代器失效。

示例:vector 的 insert()

#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {1, 2, 3};
    auto it = v.begin();  // 指向 v[0]

    v.insert(v.begin(), 0);  // 在开头插入元素

    std::cout << *it;  // ❌ UB,迭代器失效
}
✅ 解决方法
auto new_it = v.insert(v.begin(), 0);  // 重新获取有效迭代器
std::cout << *new_it;  // ✅ 安全

(3)容器扩容(push_back()resize() 导致迭代器失效)

  • vector 可能扩容(reallocate)导致所有迭代器失效
  • listmap 由于动态分配内存,不受影响

示例:vector 的 push_back()

#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {1, 2, 3};
    auto it = v.begin();  // 指向 v[0]

    v.push_back(4);  // 可能触发扩容,所有迭代器失效

    std::cout << *it;  // ❌ UB,it 失效
}
✅ 解决方法
v.reserve(10);  // 预分配足够空间,避免扩容

(4)清空容器(clear() 导致所有迭代器失效)

  • clear() 会删除所有元素,因此所有迭代器都失效
std::vector<int> v = {1, 2, 3};
auto it = v.begin();

v.clear();  // 清空容器,所有迭代器失效

std::cout << *it;  // ❌ UB

clear() 后需要重新获取迭代器!


(5)deque 特殊情况

  • dequeerase() 会导致所有后续迭代器失效,但不会影响前面的迭代器
  • push_front()push_back() 可能导致所有迭代器失效
示例
#include <deque>
#include <iostream>

int main() {
    std::deque<int> dq = {1, 2, 3, 4, 5};
    auto it = dq.begin() + 2;  // 指向 dq[2]

    dq.erase(it);  // 删除 dq[2],后续迭代器失效
}

list 不会出现此问题,因为它是双向链表,erase() 只影响当前迭代器


2. 容器迭代器失效规则

容器插入元素删除元素扩容(resize() / push_back()清空(clear()
vector可能导致扩容,所有迭代器失效失效 & 需要更新迭代器可能扩容,所有迭代器失效失效
dequepush_front() / push_back() 可能导致所有迭代器失效删除后续迭代器失效可能扩容,所有迭代器失效失效
list不影响迭代器仅当前迭代器失效不会扩容,安全失效
map/set不影响迭代器仅当前迭代器失效不会扩容,安全失效

避免 vectordeque 的迭代器失效,listmap 更安全!


3. 解决迭代器失效的方法

(1)更新迭代器

auto it = v.erase(it);  // `erase()` 返回删除元素的下一个迭代器

(2)使用索引而非迭代器

for (size_t i = 0; i < v.size(); ++i) {  // 避免迭代器失效
    if (v[i] == 3) {
        v.erase(v.begin() + i);
    }
}

(3)使用 remove_if() + erase()

v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x == 3; }), v.end());

更安全的方式,避免手动管理迭代器!


4. 结论

  • 删除元素(erase():对 vectordeque,必须更新迭代器list 影响最小。
  • 插入元素(insert()vector 可能导致扩容,所有迭代器失效
  • 容器扩容(push_back()vectordeque 可能触发所有迭代器失效
  • 清空容器(clear():所有迭代器失效。

vectordeque 迭代器失效风险高,listmap 更稳定!
使用 erase() 返回值、索引遍历、remove_if() 等方式避免迭代器失效!

🚀 牢记迭代器失效规则,写出更安全的 C++ 代码!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值