STL vector的erase操作问题

来源:互联网 发布:mindjet中文mac破解版 编辑:程序博客网 时间:2024/04/30 17:24

STL vectorerase操作问题

一老大说CSDN上有篇博文( “关于STL vectorerase操作”,地址是:http://blog.csdn.net/tingya/archive/2007/12/28/1998442.aspx)黑奇怪,抱着猎奇的心态,偶也去凑哈热闹,发现了一点问题,报告给大家。

 

作者说下面的代码是错误的:

    vector<unsigned short> m_UintVector;

    m_UintVector.push_back(10);

    m_UintVector.push_back(20);

    m_UintVector.push_back(30);

    vector<unsigned short>::iterator itr;

    itr = std::find(m_UintVector.begin(), m_UintVector.end(), 20);

    m_UintVector.erase( itr);

 

作者给出了“正确”的代码:

    vector<unsigned short> m_UintVector;

    m_UintVector.push_back(10);

    m_UintVector.push_back(20);

    m_UintVector.push_back(30);

    vector<unsigned short>::iterator itr;

    itr = std::find(m_UintVector.begin(), m_UintVector.end(), 20);

    //删除元素

    int diff = itr - m_UintVector.begin();

    m_UintVector.erase(  m_UintVector.begin() + diff );

 

我倒没看到“正确”的代码高明在哪里?姑且不考虑代码是否正确,从代码量来看,明显增加了;从代码的通用性来看,iterator + diff 这样的代码只适用随机迭代器,对list, map等等非随机类型的迭代器是不能使用的。我觉得第一种写法更漂亮通用。至于代码的正确性,我测试过,工作得很好。

 

我猜想作者这里应该没有完整描述真实的工作环境,应该还有一些限制条件没有列出来,我google了一下,发现了下面的情况:

void main()

{

    vector<int> member;

    member.push_back(1);

    member.push_back(2);

    member.push_back(2);

    member.push_back(3);

    member.push_back(1);

    member.push_back(2);

    member.push_back(4);

    vector<int>::iterator iter;

    for(iter = member.begin();

        iter != member.end();iter++)

        cout<<*iter<<endl;

 

    cout<<"do erase--------"<<endl;

 

    for(iter = member.begin();

        iter != member.end();iter++)

    {

        if(*iter == 2)

        {

            member.erase(iter);

        }

    }

    for(iter = member.begin();

        iter != member.end();iter++)

        cout<<*iter<<endl;

}

 

乍一看,这不是和上面提到的第一种方法一样吗?貌似没有问题啊。可是,要注意到,调用erase后,回到for循环又继续使用迭代器,并执行++运算。

 

好,让我们再温习一下erase函数的说明:

iterator erase ( iterator position );

iterator erase ( iterator first, iterator last );

 

现在我们只关注函数执行后的副作用和返回值。函数调用后使指向positionfirst之后的所有迭代器失效。返回值则是一个指向删除的最后一个元素后面的元素的迭代器。所以上面代码中的iter在调用erase后就无效了,我在VS2005中测试了,确实崩溃在++的操作上。

 

要解决这个问题,我们只需弃用原来的迭代器,使用返回值即可,代码如下:

for(iter = member.begin(); iter != member.end();)

{

    if(*iter == 2)

    {

        iter = member.erase(iter);

    }

    else

    {

        iter++;

    }

}

 

网络上还有很多这样的文章都没太讲清楚,比如“如何删除std::vector内的element?http://www.cnblogs.com/oomusou/archive/2006/11/15/561204.html 一文中说:若要删除std::vector中的element,正规的方式该用find() generic algorithm,若find()找到了,会传回该iterator,若找不到,将传回vector.end()。这种写法远比用for loop干净很多。

看他给出的代码:

    // Compile OK, but run-time error!!

    // for(std::vector<int>::iterator iter = ivec.begin();

    //  iter != ivec.end(); ++iter) {

    //    if (*iter == 8) {

    //      ivec.erase(iter);

    //    }

    // }

 

    // This is a RIGHT way to do it.

    std::vector<int>::iterator iter = find(ivec.begin(), ivec.end(), 8);

    if (iter != ivec.end()) {

        ivec.erase(iter);

    }

 

所以,网络上的文章看看就是了,最好是当作小说来看,猎奇一下别人的技术人生,至于是否真实是否正确,不要当真了,否则下一代堂吉诃德就要诞生了,呵呵。

原创粉丝点击