STL中使用reverse_iterator時,如何正確使用erase函數


  假設有一個list容器,順序存儲了0-9一個10個整數。現在要使用reverse_iterator迭代器來查找值為8和5的元素,並且將這兩個數刪除。先來看以下的解決方法:

 1 #include <iostream>
 2 #include <list>
 3 using namespace std;
 4 int main()
 5 {
 6     //MergeSortTest(); // 測試題目一,歸並排序
 7     //movableWindowsTest();// 測試題目二,移動窗口,輸出窗口中的最小值
 8     list<int> l;
 9     for(int i = 0;i < 10;++i)
10         l.push_back(i);// 初始化容器存入0-9十個整數
11     list<int>::reverse_iterator it;
12     int count = 2;// 記錄剩下需要刪除元素的個數
13     for(it = l.rbegin();it != l.rend() && count; ++it)
14     {
15         if(*it == 8 || *it == 5)
16         {
17             list<int>::iterator temp(it.base());// 使用base函數返回一個普通迭代器,並以此刪除指向的元素
18             ++it;
19             l.erase(temp);
20             -- count;
21         }
22     }
23     return 0;
24 }

 

  我們重點看17-19行三行代碼是否正確。這是我在不經過思考就順手寫出來的代碼,這三行代碼雖然編譯可以通過,但是是錯誤的。

  首先,我們知道不可以直接使用reverse_iterator作為參數來調用erase函數的。

  (錯誤思路)我的初始思路是希望通過it.base()函數來返回一個普通迭代器,並使用普通迭代器來刪除此元素,在刪除之前,先將迭代器指向下一個元素。

  這樣做有兩個地方引起錯誤:

    1、當it指向元素8時,it.base()返回的迭代器指向it的前一個位置,即指向元素9;

    2、使用erase刪除it.base()后,it的值未定義,即刪除后,it的值不存在了,而不是原來++it的值。

  針對錯誤1,我們可以改使用(++it).base()來返回指向正確位置的迭代器。(請注意不要使用++it.base(),這樣做修改返回值,是極不推薦的做法)。

  針對錯誤2,我們需要知道,erase函數的返回值就是 刪除該元素后指向的下一個位置的迭代器。因此只要記錄下erase的返回值,就能正確獲得it的值。

  根據以上兩點說法,將代碼13-21行修改為

 1     for(it = l.rbegin();it != l.rend() && count;)
 2     {
 3         if(*it == 8 || *it == 5)
 4         {
 5             list<int>::iterator iter = l.erase((++it).base());// 記錄刪除該元素后的指向下一個位置的迭代器(注意刪除8時,下一個是9)
 6             it = list<int>::reverse_iterator(iter);// 將該迭代器轉換為reverse_iterator,此時it指向7
 7             -- count;
 8         }
 9         else
10             ++it;
11     }

  以上代碼變可以成功刪除容器中的5和8兩個元素,並使容器中存儲的為1,2,3,4,6,7,9.

  到此,仍有一個需要特別留意的問題:上面的第5行代碼,刪除8時,得出的iter指向的“下一個元素”是9,而不是7。而第六行執行完以后,it指向的是7

  其實這個應該挺好理解,但是在下水平有限,不太會解釋。指出這一點是為了讓大家多留個神,否則容易給自己挖了個坑。詳細解釋請查閱其他資料。以下為正確的完整代碼寫法:

#include <iostream>
#include <list>
using namespace std;
int main()
{
    //MergeSortTest(); // 測試題目一,歸並排序
    //movableWindowsTest();// 測試題目二,移動窗口,輸出窗口中的最小值
    list<int> l;
    for(int i = 0;i < 10;++i)
        l.push_back(i);// 初始化容器存入0-9十個整數
    list<int>::reverse_iterator it;
    int count = 2;// 記錄剩下需要刪除元素的個數
    for(it = l.rbegin();it != l.rend() && count;)
    {
        if(*it == 8 || *it == 5)
        {
            list<int>::iterator iter = l.erase((++it).base());// 記錄刪除該元素后的指向下一個位置的迭代器(注意刪除8時,下一個是9)
            it = list<int>::reverse_iterator(iter);// 將該迭代器轉換為reverse_iterator,此時it指向7
            -- count;
        }
        else
            ++it;
    }
    for(list<int>::iterator iter = l.begin();iter != l.end();++iter)
        cout << *iter << " ";
    cout << endl;
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM