迭代器失效及其解决方法

目录

前言

一、常见容器中的迭代器失效情况

二、迭代器失效的常见场景及解决方法

1. 迭代器失效后继续使用导致未定义行为

2. 避免在循环中修改容器

3. 避免 vector 中频繁插入导致迭代器失效

4. 在 map 或 set 中删除元素时避免迭代器失效


前言

  • 迭代器失效的主要原因:对容器进行插入、删除或内存重新分配的操作。
  • 如何解决迭代器失效
    1. 插入或删除操作后,重新获取迭代器。
    2. 遍历容器时删除元素,使用 erase() 的返回值获取下一个有效迭代器。
    3. 使用 vector::reserve() 预先分配内存,减少插入操作导致的迭代器失效。
    4. 删除 mapset 元素时,依赖 erase() 的返回值避免迭代器失效。

在使用容器(如 vector, map, set, 等)进行操作时,迭代器失效(Iterator Invalidation)是一个常见问题。迭代器失效指的是:在对容器进行修改(如插入、删除、重分配)后,先前的迭代器、指针或引用可能不再有效,访问它们会导致未定义行为。

一、常见容器中的迭代器失效情况

  1. vector

    • 插入元素
      • 如果在容器中插入元素,并且导致 vector 重新分配内存(即容器容量不足,触发了动态扩展),则所有迭代器、指针、引用都会失效。
      • 如果没有内存重新分配,仅仅插入到容器的中间或末尾,则插入位置后的迭代器失效。
    • 删除元素
      • 当元素被删除时,被删除元素后的迭代器会失效。因为元素删除后,其后的元素会向前移动以填补空位。
  2. deque

    • 插入或删除元素
      • 插入或删除操作可能会导致容器的内存重新分配,导致所有迭代器失效。
      • 插入或删除位于容器中间时,所有的迭代器都可能失效;但在两端插入时,只有两端的迭代器可能失效。
  3. list / forward_list

    • 插入元素
      • 插入元素不会使任何迭代器失效。因为 list 是链表结构,不涉及内存重新分配。
    • 删除元素
      • 删除元素后,只有指向被删除元素的迭代器失效,其他迭代器保持有效。
  4. map / set / unordered_map / unordered_set

    • 插入元素
      • 插入新元素不会使现有的迭代器失效,因为这些容器底层采用平衡树或哈希表实现,插入时不会影响现有的元素位置。
    • 删除元素
      • 删除元素时,指向被删除元素的迭代器会失效,但其他迭代器不会失效。

二、迭代器失效的常见场景及解决方法

1. 迭代器失效后继续使用导致未定义行为

  • 场景:你对 vector 进行插入操作后,试图使用插入前的迭代器。
  • 解决方法
    • 在插入或删除操作之后,重新获取有效的迭代器。
    • 对于 vector,在插入元素后需要更新或重新计算迭代器。例如:
std::vector<int> vec = {1, 2, 3};
auto it = vec.begin();
vec.push_back(4);  // 可能导致重新分配内存,失效之前的迭代器
// 重新获取迭代器
it = vec.begin();

2. 避免在循环中修改容器

  • 场景:在遍历容器时同时删除元素,导致迭代器失效。
  • 解决方法
    • 使用安全的迭代器操作,例如 erase() 函数在 vectorlist 中返回一个指向下一个有效元素的迭代器。
    • 使用迭代器返回的值避免使用失效的迭代器。
    • 示例:
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); ) {
    if (*it % 2 == 0) {
        it = vec.erase(it);  // erase 返回指向下一个有效元素的迭代器
    } else {
        ++it;
    }
}

3. 避免 vector 中频繁插入导致迭代器失效

  • 场景:频繁插入 vector 导致内存重新分配,迭代器失效。
  • 解决方法
    • 在使用 push_back() 等插入操作前,使用 reserve() 预分配足够的内存以避免重新分配。
    • 示例:
std::vector<int> vec;
vec.reserve(100);  // 预分配内存,减少插入时的重新分配
for (int i = 0; i < 100; ++i) {
    vec.push_back(i);  // 不会导致迭代器失效
}

4. mapset 中删除元素时避免迭代器失效

  • 场景:在 mapset 中删除元素时,指向被删除元素的迭代器失效。
  • 解决方法
    • 使用 erase() 返回值来获取下一个有效的迭代器。
    • 示例:
std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};
for (auto it = myMap.begin(); it != myMap.end(); ) {
    if (it->first == 2) {
        it = myMap.erase(it);  // erase 返回下一个有效迭代器
    } else {
        ++it;
    }
}
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值