本文根据常用的容器来总结迭代器失效的几种情况。

1. 序列式容器:vector、deque,数组型或队列型数据结构。该数据结构分配在连续的内存中,当删除一个元素后,内存中的数据会发生移动以保证数据的紧凑。所以删除一个元素后,其他数据的地址发生了变化,之前获取的迭代器根据原有信息就访问不到正确的数据。

解决方法:erase返回下一个有效迭代器的值,itVec=vecData.erase(itVec)。

std::vector<int> vecData;
vecData.push_back(1);
vecData.push_back(2);
vecData.push_back(3);
vecData.push_back(4);

std::vector<int>::iteator itVec = vecData.begin();
while (itVec != vecData.end())
{
    if (*itVec % 2 == 0)
    {
        itVec = vecData.erase(itVec);    // 不能使用vecData.erase(itVec++);迭代器会失效
    }
    else
    {
        itVec++;
    }
}

2. 关联容器:map、set、multiset、map、multimap,树形数据结构。以红黑树或者平衡二叉树组织数据,虽然删除了一个元素,整棵树也会调整,以符合红黑树或者二叉树的规范,但是单个节点在内存中的地址没有变化,变化的是各节点之间的指向关系。删除一个结点不会对其他结点造成影响。erase迭代器只是被删元素的迭代器失效。

解决办法:
1). C++98中map的erase返回值为void,只能使用mapData.erase(itMap++); 先把itMap传值到erase里面,然后itMap自增,最后执行erase,所以itMap在失效前已经自增了  
2). C++11中map的erase可以返回下一个有效迭代器,即itMap=vecMap.erase(itMap);  或者mapData.erase(itMap++);

std::map<string, int> mapData;
mapData["a"] = 1;
mapData["b"] = 2;
mapData["c"] = 3;

std::map<string, int>::iterator itMap = mapData.begin();
while (itMap != mapData.end())
{
    if (strcmp(itMap->first.c_str(), "a") == 0)
    {
        mapData.erase(itMap++);    // C++11中也可以用:itMap = mapData.erase(itMap);
    }
    else
    {
        itMap++;
    }

    /* 以下代码会使迭代器失效
    if (strcmp(itMap->first.c_str(), "a") == 0)
    {
        mapData.erase(itMap);
    }
    itMap++;
    */
}

3. 列表容器:list,链表型数据结构。双向链表,使用不连续分配的内存,删除运算使指向删除位置的迭代器失效,不会使其他迭代器失效。

解决办法:
1). erase返回下一个有效迭代器的值,itList = lstData.erase(itList);               
2). lstData.erase(itList++);

std::list<int> lstData;
lstData.push_back(1);
lstData.push_back(2);
lstData.push_back(3);
lstData.push_back(4);

std::list<int>::iteator itList = lstData.begin();
while (itList != lstData.end())
{
    if (*itList % 2 == 0)
    {
        itList = lstData.erase(itList);    // 也可以使用lstData.erase(itList++);
    }
    else
    {
        itList++;
    }
}

注意:迭代器失效会使程序崩溃,或者出现无法预料的结果。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐