容器内部删除一个元素,迭代器失效问题

474 阅读2分钟
  1. 顺序容器(序列式容器,比如vector、deque)

erase迭代器不仅使所指向被删除的迭代器失效,而且使被删元素之后的所有迭代器失效(list除外),所以不能使用erase(it++)的方式,但是erase的返回值是下一个有效迭代器;

It = c.erase(it);

  1. 关联容器(关联式容器,比如map、set、multimap、multiset等)

erase迭代器只是被删除元素的迭代器失效,但是返回值是void,所以要采用erase(it++)的方式删除迭代器;

c.erase(it++)

#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};

    // 错误示例:在循环中直接修改容器
    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        if (it->first % 2 == 0) {
            myMap.erase(it); // 这会导致迭代器失效
        }
    }

    // 正确示例:在循环外部调用 erase 函数
    for (auto it = myMap.begin(); it != myMap.end();) {
        if (it->first % 2 == 0) {
            it = myMap.erase(it); // 使用返回值更新迭代器
        } else {
            ++it;
        }
    }

    // 输出剩余的键值对
    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}


在C++中,当你删除容器中的一个元素时,可能会导致迭代器失效。这是因为删除一个元素后,容器中的其他元素可能会发生重排,迭代器指向的位置可能会改变。

例如,对于vector、list、deque等容器,使用erase()函数删除元素将导致迭代器失效。要避免这个问题,可以通过以下几种方式:

  1. 使用返回新的迭代器的erase()函数重载:

    iterator erase(iterator position);
    iterator erase(iterator first, iterator last);
    

    这种方式允许你在删除元素后获得一个新的有效迭代器。

  2. 使用算法remove()和erase()组合:

    iterator newEnd = remove(container.begin(), container.end(), value);
    container.erase(newEnd, container.end());
    

    这种方式先使用remove()算法将要删除的元素移到容器的末尾,再使用erase()函数删除这些元素,确保迭代器不会失效。

  3. 使用智能指针进行元素管理: 如果你将元素存储在智能指针中,删除元素时只会改变指针的引用计数,而不会导致迭代器失效。

  4. 使用索引而不是迭代器: 对于支持随机访问的容器(如vector),可以使用索引访问元素,而不是使用迭代器。删除元素后,索引位置仍然有效。

无论哪种方式,都需要谨慎处理迭代器失效的问题,避免在失效的迭代器上执行操作,以免引发未定义行为。