在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法

在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法

转自:http://blog.csdn.net/kesalin/article/details/24265303

众所周知,在使用迭代器遍历 STL 容器时,需要特别留意是否在循环中修改了迭代器而导致迭代器失效的情形。下面我来总结一下在对各种容器进行正向和反向遍历过程中删除元素时,正确更新迭代器的用法。本文源码:https://code.csdn.net/snippets/173595

首先,要明白使用正向迭代器(iterator)进行反向遍历是错误的用法,要不干嘛要有反向迭代器呢(reverse_iterator)。其次,根据容器的特性,遍历删除操作的用法可以分为两组,第一组是 list 和 vector,第二组是 map 和 set。

 

接下来,看看具体怎么个用法。

第一种情形:正向遍历删除元素

对 list 和 vector 来说,它们的 erase 函数会返回下一个迭代器,因此在遍历时,只需要 it = c.erase(it); 即可。

对 map 和 set 来说,它们的 erase 函数返回的 void,而在进行 erase 之后,当前迭代器会失效,无法再用于获取下一个迭代器。因此需要 erase 之前就获取指向下一个元素的迭代器。如:

tmpIt = it;  
++it;  
c.erase(tmpIt); 

利用后缀++操作符的特性(先创建副本,然后再递增迭代器,然后返回副本)上面的三行代码可以简化为一行:

c.erase(it++);  

list 正向遍历删除元素示例(vector 用法相同):

list<int>::iterator it;  
for (it = l.begin(); it != l.end();)  
{  
    if (0 == (*it) % 2) {  
        it = l.erase(it);  
    }  
    else {  
        ++it;  
    }  
} 

map 正向遍历删除元素示例(set 用法相同)

map<int, int>::iterator mit;  
for (mit = m.begin(); mit != m.end();)  
{  
    if (0 == mit->first % 2) {  
        m.erase(mit++);  
    }  
    else {  
        ++mit;  
    }  
}

第二种情形,反向遍历删除元素

 

关于正向/反向迭代器的关系,请参考《Effective STL》,在这里我只说明一点,两者相差一个元素,从一个反向迭代器获得对应的正向迭代器需要使用 base() 方法。如下图所示:ri 是指向元素3的反向迭代器,而 i 是 ri.base() 所得到的正想迭代器。

由于所有的 erase 函数都只接受正向迭代器 iterator,所以在进行反向遍历删除元素时,首先需要将 reverse_iterator 转换为 iterator,然后再考虑更新迭代器的问题。

先来分析如何将 reverse_iterator 转换为 iterator。如上图所示,我们想要删除元素3,而 ri.base() 所得到的正向迭代器 i 指向的其实 4 了,因而为了正确地删除元素 3,需要将ri往前(反向的)挪一个位置。也就是说,这一步的删除用法应为:

c.erase((++rit).base()); 

或:(想想为什么?,但这个用法不具备可移植性,因为有些 STL 实现不允许修改函数返回的指针)

c.erase(--(rit.base(); 

然后,我们来分析迭代器更新的问题。
对 list/vector 来说,由于的 erase 能够返回一个有效的正向迭代器,因而只需要将返回的正向迭代器转换为反向迭代器即可。

对 map/set 来说,因为在进行删除操作 l.erase((++rit).base()) 时,迭代器已经更新过了,真是一举两得啊。从这里也可以看出,使用这种先递增后 base() 的转换删除法,代码更清晰。

至此,理论分析完毕,下面我们来看具体的实例。

list 反向遍历删除元素示例(vector 用法相同):

// erase with reverse_iterator  
list<int>::reverse_iterator rit;  
for (rit = l.rbegin(); rit != l.rend();)  
{  
    if (0 == (*rit) % 2) {  
        rit = list<int>::reverse_iterator(l.erase((++rit).base()));  
    }  
    else {  
        ++rit;  
    }  
}

map 反向遍历删除元素示例(set 用法相同):

// erase with reverse_iterator  
map<int, int>::reverse_iterator rit;  
for (rit = m.rbegin(); rit != m.rend();)  
{  
    if (0 == rit->first % 2) {  
        m.erase((++rit).base());  
    }  
    else {  
        ++rit;  
    }  
}  

OK,删除用法相信大家都明白了,但是,但是,引起迭代器失效的操作还有插入操作呀,相信聪明的你一定能够举一反三正确更新迭代器~~

  所有实例的参考代码如下:

//============================================================================
// Name        : TestSTL.cpp
// Author      : kesalin@gmail.com
// Version     : version 0.1
// Copyright   : kesalin@gmail.com
// Description : http://blog.csdn.net/kesalin/
//============================================================================

#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>

using namespace std;

void printList(list<int>& l, const char* info)
{
    cout << "list values: " << info;
    list<int>::iterator it;
    for (it = l.begin(); it != l.end(); ++it)
    {
        if (it != l.begin()) cout << ", ";
        cout << *it;
    }
    cout << endl;
}

void printVector(vector<int>& v, const char* info)
{
    cout << "vector values: " << info;
    vector<int>::iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        if (it != v.begin()) cout << ", ";
        cout << *it;
    }
    cout << endl;
}

void printMap(map<int, int>& m, const char* info)
{
    cout << "map values: " << info;
    map<int, int>::iterator it;
    for (it = m.begin(); it != m.end(); ++it)
    {
        if (it != m.begin()) cout << ", ";
        cout << "(" << it->first << ", " << it->second << ")";
    }
    cout << endl;
}

void printSet(set<int>& s, const char* info)
{
    cout << "set values: " << info;
    set<int>::iterator it;
    for (it = s.begin(); it != s.end(); ++it)
    {
        if (it != s.begin()) cout << ", ";
        cout << *it;
    }
    cout << endl;
}

void vectorErase()
{
    cout << "\n====================== vector erase ======================" << endl;
    vector<int> v;

    // initialize
    for (int i = 0; i < 5; ++i) {
        v.push_back(i);
    }

    // erase with iterator
    printVector(v, "Before erase with iterator: ");
    vector<int>::iterator vit;
    for (vit = v.begin(); vit != v.end();)
    {
        if (0 == (*vit) % 2) {
            vit = v.erase(vit);
        }
        else {
            ++vit;
        }
    }
    printVector(v, "After erase with iterator: ");

    // reset
    v.clear();
    for (int i = 0; i < 5; ++i) {
        v.push_back(i);
    }

    // erase with reverse_iterator
    printVector(v, "Before erase with reverse_iterator: ");
    vector<int>::reverse_iterator vrit;
    for (vrit = v.rbegin(); vrit != v.rend();)
    {
        if (0 == (*vrit) % 2) {
            vrit = vector<int>::reverse_iterator(v.erase((++vrit).base()));
        }
        else {
            ++vrit;
        }
    }
    printVector(v, "After erase with reverse_iterator: ");
}

void listErase()
{
    cout << "\n====================== list erase ======================" << endl;
    list<int> l;

    // initialize
    for (int i = 0; i < 5; ++i) {
        l.push_back(i);
    }

    // erase with iterator
    printList(l, "Before erase with iterator: ");
    list<int>::iterator it;
    for (it = l.begin(); it != l.end();)
    {
        if (0 == (*it) % 2) {
            it = l.erase(it);
        }
        else {
            ++it;
        }
    }
    printList(l, "After erase with iterator: ");

    // reset
    l.clear();
    for (int i = 0; i < 5; ++i) {
        l.push_back(i);
    }

    // erase with reverse_iterator
    printList(l, "Before erase with reverse_iterator: ");
    list<int>::reverse_iterator rit;
    for (rit = l.rbegin(); rit != l.rend();)
    {
        if (0 == (*rit) % 2) {
            rit = list<int>::reverse_iterator(l.erase((++rit).base()));
            //rit = list<int>::reverse_iterator(l.erase(--(rit.base()));
        }
        else {
            ++rit;
        }
    }
    printList(l, "After erase with reverse_iterator: ");
}

void mapErase()
{
    cout << "\n====================== map erase ======================" << endl;
    map<int, int> m;

    // initialize
    for (int i = 0; i < 5; ++i) {
        m[i] = i;
    }

    // erase with iterator
    printMap(m, "Before erase with iterator: ");
    map<int, int>::iterator mit;
    for (mit = m.begin(); mit != m.end();)
    {
        if (0 == mit->first % 2) {
            m.erase(mit++);
        }
        else {
            ++mit;
        }
    }
    printMap(m, "After erase with iterator: ");

    // reset
    m.clear();
    for (int i = 0; i < 5; ++i) {
        m[i] = i;
    }

    // erase with reverse_iterator
    printMap(m, "Before erase with reverse_iterator: ");
    map<int, int>::reverse_iterator rit;
    for (rit = m.rbegin(); rit != m.rend();)
    {
        if (0 == rit->first % 2) {
            m.erase((++rit).base());
        }
        else {
            ++rit;
        }
    }
    printMap(m, "After erase with reverse_iterator: ");
}

void setErase()
{
    cout << "\n====================== set erase ======================" << endl;
    set<int> s;

    // initialize
    for (int i = 0; i < 5; ++i) {
        s.insert(i);
    }

    // erase with iterator
    printSet(s, "Before erase with iterator: ");
    set<int>::iterator sit;
    for (sit = s.begin(); sit != s.end();)
    {
        if (0 == (*sit) % 2) {
            s.erase(sit++);
        }
        else {
            ++sit;
        }
    }
    printSet(s, "After erase with iterator: ");

    // reset
    s.clear();
    for (int i = 0; i < 5; ++i) {
        s.insert(i);
    }

    // erase with reverse_iterator
    printSet(s, "Before erase with reverse_iterator: ");
    set<int>::reverse_iterator rit;
    for (rit = s.rbegin(); rit != s.rend();)
    {
        if (0 == (*rit) % 2) {
            s.erase((++rit).base());
        }
        else {
            ++rit;
        }
    }
    printSet(s, "After erase with reverse_iterator: ");
}

int main()
{
    vectorErase();
    listErase();
    mapErase();
    setErase();
    return 0;
}
View Code

 

posted @ 2017-12-05 15:55  flylong0204  阅读(711)  评论(0)    收藏  举报